diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 09e7cbaded..55ef4a8c40 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,7 +9,7 @@ updates: - dependency-name: "axum" versions: ["> 0.7.4"] - package-ecosystem: "docker" - directory: "/cli/docker" + directory: "/crates/cli/docker" schedule: interval: "weekly" target-branch: "dev" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index b490ff2d2e..14439d5560 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -85,8 +85,8 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v6 with: - context: ./cli/docker - file: ./cli/docker/Dockerfile + context: ./crates/cli/docker + file: ./crates/cli/docker/Dockerfile push: true tags: ${{ steps.docker_tagging.outputs.docker_tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02e6535f4f..aa46c6c101 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,12 +5,7 @@ on: branches: - main paths: - - "cli/**" - - "core/**" - - "prover/**" - - "recursion/**" - - "derive/**" - - "sdk/**" + - "crates/**" - ".github/workflows/**" concurrency: @@ -118,18 +113,18 @@ jobs: - name: Install SP1 CLI run: | - cd cli + cd crates/cli cargo install --force --locked --path . cd ~ - name: Run script run: | cd examples/ssz-withdrawals/program - cargo add sp1-zkvm --path $GITHUB_WORKSPACE/zkvm/entrypoint + cargo add sp1-zkvm --path $GITHUB_WORKSPACE/crates/zkvm/entrypoint cargo prove build cd ../script cargo remove sp1-sdk - cargo add sp1-sdk --path $GITHUB_WORKSPACE/sdk + cargo add sp1-sdk --path $GITHUB_WORKSPACE/crates/sdk SP1_DEV=1 RUST_LOG=info cargo run --release tendermint: @@ -158,16 +153,16 @@ jobs: - name: Install SP1 CLI run: | - cd cli + cd crates/cli cargo install --force --locked --path . cd ~ - name: Run script run: | cd examples/tendermint/program - cargo add sp1-zkvm --path $GITHUB_WORKSPACE/zkvm/entrypoint + cargo add sp1-zkvm --path $GITHUB_WORKSPACE/crates/zkvm/entrypoint cargo prove build cd ../script cargo remove sp1-sdk - cargo add sp1-sdk --path $GITHUB_WORKSPACE/sdk + cargo add sp1-sdk --path $GITHUB_WORKSPACE/crates/sdk SP1_DEV=1 RUST_LOG=info cargo run --release diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 082da895a8..2d7673efe7 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -7,14 +7,7 @@ on: branches: - "**" paths: - - "cli/**" - - "core/**" - - "prover/**" - - "recursion/**" - - "derive/**" - - "sdk/**" - - "zkvm/**" - - "tests/**" + - "crates/**" - "examples/**" - "Cargo.toml" - ".github/workflows/**" @@ -25,6 +18,39 @@ concurrency: cancel-in-progress: true jobs: + test-fast: + name: Test (fast-experimental) + runs-on: runs-on,runner=64cpu-linux-x64,spot=false + env: + CARGO_NET_GIT_FETCH_WITH_CLI: "true" + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Setup CI + uses: ./.github/actions/setup + + - name: Run cargo check + uses: actions-rs/cargo@v1 + with: + command: check + toolchain: 1.79.0 + args: --all-targets --all-features + + - name: Run cargo test core-v2 + uses: actions-rs/cargo@v1 + with: + command: test + toolchain: 1.79.0 + args: --release --package sp1-recursion-core-v2 --package sp1-recursion-circuit-v2 --features native-gnark + env: + RUSTFLAGS: -Copt-level=3 -Cdebug-assertions -Coverflow-checks=y -Cdebuginfo=0 -C target-cpu=native + RUST_BACKTRACE: 1 + FRI_QUERIES: 1 + SP1_DEV: 1 + + + test-x86: name: Test (x86-64) runs-on: @@ -147,7 +173,7 @@ jobs: - name: Install SP1 CLI run: | - cd cli + cd crates/cli cargo install --force --locked --path . ~/.sp1/bin/cargo-prove prove install-toolchain cd ~ @@ -177,7 +203,7 @@ jobs: - name: Install SP1 CLI run: | - cd cli + cd crates/cli cargo install --force --locked --path . cd ~ @@ -189,9 +215,9 @@ jobs: run: | cd fibonacci cd program - cargo add sp1-zkvm --path $GITHUB_WORKSPACE/zkvm/entrypoint + cargo add sp1-zkvm --path $GITHUB_WORKSPACE/crates/zkvm/entrypoint cargo prove build cd ../script cargo remove sp1-sdk - cargo add sp1-sdk --path $GITHUB_WORKSPACE/sdk + cargo add sp1-sdk --path $GITHUB_WORKSPACE/crates/sdk SP1_DEV=1 RUST_LOG=info cargo run --release -- --prove diff --git a/.vscode/settings.json b/.vscode/settings.json index ad9ab59b7b..7e4fd0ca18 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,8 @@ // // Examples. // "examples/chess/program/Cargo.toml", // "examples/chess/script/Cargo.toml", + // "examples/cycle-tracking/program/Cargo.toml", + // "examples/cycle-tracking/script/Cargo.toml", // "examples/fibonacci/program/Cargo.toml", // "examples/fibonacci/script/Cargo.toml", // "examples/io/program/Cargo.toml", diff --git a/Cargo.lock b/Cargo.lock index fef990f3c6..c94250fb4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1226,6 +1226,84 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "dashu" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b3e5ac1e23ff1995ef05b912e2b012a8784506987a2651552db2c73fb3d7e0" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-macros", + "dashu-ratio", + "rustversion", +] + +[[package]] +name = "dashu-base" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b80bf6b85aa68c58ffea2ddb040109943049ce3fbdf4385d0380aef08ef289" + +[[package]] +name = "dashu-float" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85078445a8dbd2e1bd21f04a816f352db8d333643f0c9b78ca7c3d1df71063e7" +dependencies = [ + "dashu-base", + "dashu-int", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-int" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee99d08031ca34a4d044efbbb21dff9b8c54bb9d8c82a189187c0651ffdb9fbf" +dependencies = [ + "cfg-if", + "dashu-base", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93381c3ef6366766f6e9ed9cf09e4ef9dec69499baf04f0c60e70d653cf0ab10" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-ratio", + "paste", + "proc-macro2", + "quote", + "rustversion", +] + +[[package]] +name = "dashu-ratio" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33b04dd7ce1ccf8a02a69d3419e354f2bbfdf4eb911a0b7465487248764c9" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "num-modular", + "num-order", + "rustversion", +] + [[package]] name = "der" version = "0.7.9" @@ -1409,6 +1487,12 @@ 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 = "encode_unicode" version = "0.3.6" @@ -2968,6 +3052,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -3684,12 +3783,13 @@ checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -4642,18 +4742,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.207" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" dependencies = [ "proc-macro2", "quote", @@ -4884,17 +4984,18 @@ dependencies = [ [[package]] name = "sp1-build" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "anyhow", "cargo_metadata", + "chrono", "clap", "dirs", ] [[package]] name = "sp1-cli" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "anstyle", "anyhow", @@ -4916,7 +5017,7 @@ dependencies = [ "serde", "serde_json", "sp1-build", - "sp1-core", + "sp1-core-machine", "sp1-prover", "sp1-sdk", "target-lexicon", @@ -4928,8 +5029,43 @@ dependencies = [ ] [[package]] -name = "sp1-core" -version = "1.1.1" +name = "sp1-core-executor" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "bytemuck", + "elf", + "eyre", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "nohash-hasher", + "num", + "p3-field", + "p3-keccak-air", + "p3-maybe-rayon", + "rand", + "rrs-succinct", + "serde", + "serde_with", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "sp1-zkvm", + "strum", + "strum_macros", + "thiserror", + "tiny-keccak", + "tracing", + "typenum", +] + +[[package]] +name = "sp1-core-machine" +version = "1.2.0-rc1" dependencies = [ "anyhow", "arrayref", @@ -4975,8 +5111,11 @@ dependencies = [ "serde_with", "size", "snowbridge-amcl", + "sp1-core-executor", + "sp1-curves", "sp1-derive", "sp1-primitives", + "sp1-stark", "sp1-zkvm", "static_assertions", "strum", @@ -4992,47 +5131,77 @@ dependencies = [ ] [[package]] -name = "sp1-derive" -version = "1.1.1" +name = "sp1-cuda" +version = "1.2.0-rc1" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bincode", + "ctrlc", + "prost", + "prost-build", + "prost-types", + "serde", + "serde_json", + "sp1-core-machine", + "sp1-prover", + "sp1-stark", + "tokio", + "tracing", + "tracing-subscriber", + "twirp-build-rs", + "twirp-rs", ] [[package]] -name = "sp1-eval" -version = "1.1.1" +name = "sp1-curves" +version = "1.2.0-rc1" dependencies = [ - "clap", - "csv", + "curve25519-dalek", + "dashu", + "elliptic-curve", + "generic-array 1.1.0", + "itertools 0.13.0", + "k256", + "num", + "p3-field", + "rand", "serde", - "sp1-core", - "sp1-prover", + "snowbridge-amcl", + "sp1-primitives", + "sp1-stark", + "typenum", +] + +[[package]] +name = "sp1-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "sp1-helper" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ - "cargo_metadata", - "chrono", "sp1-build", ] [[package]] name = "sp1-lib" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-primitives" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "itertools 0.13.0", "lazy_static", @@ -5044,7 +5213,7 @@ dependencies = [ [[package]] name = "sp1-prover" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", @@ -5064,13 +5233,15 @@ dependencies = [ "serde", "serde_json", "serial_test", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-circuit", "sp1-recursion-compiler", "sp1-recursion-core", "sp1-recursion-gnark-ffi", "sp1-recursion-program", + "sp1-stark", "subtle-encoding", "tempfile", "thiserror", @@ -5080,7 +5251,7 @@ dependencies = [ [[package]] name = "sp1-recursion-circuit" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "bincode", "ff 0.13.0", @@ -5100,20 +5271,61 @@ dependencies = [ "p3-util", "rand", "serde", - "sp1-core", + "sp1-core-machine", "sp1-recursion-compiler", "sp1-recursion-core", "sp1-recursion-derive", "sp1-recursion-gnark-ffi", "sp1-recursion-program", + "sp1-stark", + "zkhash", +] + +[[package]] +name = "sp1-recursion-circuit-v2" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rand", + "serde", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-circuit", + "sp1-recursion-compiler", + "sp1-recursion-core-v2", + "sp1-recursion-derive", + "sp1-recursion-gnark-ffi", + "sp1-recursion-program", + "sp1-stark", + "stacker", + "tracing", "zkhash", ] [[package]] name = "sp1-recursion-compiler" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "backtrace", + "criterion", "itertools 0.13.0", "p3-air", "p3-baby-bear", @@ -5129,17 +5341,21 @@ dependencies = [ "p3-symmetric", "p3-util", "rand", + "rayon", "serde", - "sp1-core", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-core", + "sp1-recursion-core-v2", "sp1-recursion-derive", + "sp1-stark", "tracing", + "vec_map", ] [[package]] name = "sp1-recursion-core" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "arrayref", "backtrace", @@ -5164,17 +5380,59 @@ dependencies = [ "rand", "serde", "serde_with", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-derive", "sp1-primitives", + "sp1-stark", "static_assertions", "tracing", "zkhash", ] +[[package]] +name = "sp1-recursion-core-v2" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rand", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-recursion-core", + "sp1-stark", + "static_assertions", + "thiserror", + "tracing", + "vec_map", + "zkhash", +] + [[package]] name = "sp1-recursion-derive" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "proc-macro2", "quote", @@ -5183,7 +5441,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-cli" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "bincode", "clap", @@ -5192,7 +5450,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", @@ -5209,14 +5467,15 @@ dependencies = [ "serde", "serde_json", "sha2", - "sp1-core", + "sp1-core-machine", "sp1-recursion-compiler", + "sp1-stark", "tempfile", ] [[package]] name = "sp1-recursion-program" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "itertools 0.13.0", "p3-air", @@ -5234,17 +5493,19 @@ dependencies = [ "p3-util", "rand", "serde", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-compiler", "sp1-recursion-core", + "sp1-stark", "stacker", "tracing", ] [[package]] name = "sp1-sdk" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "alloy-sol-types", "anyhow", @@ -5271,8 +5532,11 @@ dependencies = [ "serde", "serde_json", "sha2", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", + "sp1-cuda", "sp1-prover", + "sp1-stark", "strum", "strum_macros", "sysinfo", @@ -5285,28 +5549,37 @@ dependencies = [ ] [[package]] -name = "sp1-server" -version = "1.1.1" +name = "sp1-stark" +version = "1.2.0-rc1" dependencies = [ - "bincode", - "ctrlc", - "prost", - "prost-build", - "prost-types", + "arrayref", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rayon-scan", "serde", - "serde_json", - "sp1-core", - "sp1-prover", - "tokio", + "sp1-derive", + "sp1-primitives", + "sp1-zkvm", "tracing", - "tracing-subscriber", - "twirp-build-rs", - "twirp-rs", ] [[package]] name = "sp1-zkvm" -version = "1.1.1" +version = "1.2.0-rc1" dependencies = [ "bincode", "cfg-if", @@ -5978,9 +6251,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "untrusted" @@ -6033,6 +6306,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "vergen" version = "8.3.2" diff --git a/Cargo.toml b/Cargo.toml index d8f2f3e391..a648917797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,39 @@ -[workspace] -members = [ - "build", - "cli", - "core", - "derive", - "eval", - "helper", - "primitives", - "prover", - "recursion/circuit", - "recursion/compiler", - "recursion/core", - "recursion/derive", - "recursion/gnark-cli", - "recursion/gnark-ffi", - "recursion/program", - "server", - "sdk", - "zkvm/*", -] -exclude = ["examples/target"] -resolver = "2" - [workspace.package] -version = "1.1.1" +version = "1.2.0-rc1" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/succinctlabs/sp1" keywords = ["sp1", "succinct", "zero-knowledge", "zkvm"] categories = ["cryptography"] +[workspace] +members = [ + "crates/build", + "crates/cli", + "crates/core/executor", + "crates/core/machine", + "crates/curves", + "crates/derive", + "crates/helper", + "crates/primitives", + "crates/prover", + "crates/recursion/circuit", + "crates/recursion/circuit-v2", + "crates/recursion/compiler", + "crates/recursion/core", + "crates/recursion/core-v2", + "crates/recursion/derive", + "crates/recursion/gnark-cli", + "crates/recursion/gnark-ffi", + "crates/recursion/program", + "crates/sdk", + "crates/cuda", + "crates/stark", + "crates/zkvm/*", +] +exclude = ["examples/target"] +resolver = "2" + [profile.release] opt-level = 3 @@ -42,24 +46,30 @@ debug = true debug-assertions = true [workspace.dependencies] -sp1-build = { path = "build", version = "1.1.0" } -sp1-derive = { path = "derive", version = "1.1.0" } -sp1-core = { path = "core", version = "1.1.0" } -sp1-cli = { path = "cli", version = "1.1.0", default-features = false } -sp1-eval = { path = "eval", version = "1.1.0", default-features = false } -sp1-helper = { path = "helper", version = "1.1.0", default-features = false } -sp1-primitives = { path = "primitives", version = "1.1.0" } -sp1-prover = { path = "prover", version = "1.1.0" } -sp1-recursion-compiler = { path = "recursion/compiler", version = "1.1.0" } -sp1-recursion-core = { path = "recursion/core", version = "1.1.0", default-features = false } -sp1-recursion-derive = { path = "recursion/derive", version = "1.1.0", default-features = false } -sp1-recursion-gnark-ffi = { path = "recursion/gnark-ffi", version = "1.1.0", default-features = false } -sp1-recursion-program = { path = "recursion/program", version = "1.1.0", default-features = false } -sp1-recursion-circuit = { path = "recursion/circuit", version = "1.1.0", default-features = false } -sp1-sdk = { path = "sdk", version = "1.1.0" } -sp1-server = { path = "server", version = "1.1.0" } -sp1-lib = { path = "zkvm/lib", version = "1.1.0", default-features = false } -sp1-zkvm = { path = "zkvm/entrypoint", version = "1.1.0", default-features = false } +# sp1 +sp1-build = { path = "crates/build", version = "1.2.0-rc1" } +sp1-core-machine = { path = "crates/core/machine", version = "1.2.0-rc1" } +sp1-core-executor = { path = "crates/core/executor", version = "1.2.0-rc1" } +sp1-derive = { path = "crates/derive", version = "1.2.0-rc1" } +sp1-cli = { path = "crates/cli", version = "1.2.0-rc1", default-features = false } +sp1-curves = { path = "crates/curves", version = "1.2.0-rc1" } +sp1-helper = { path = "crates/helper", version = "1.2.0-rc1", default-features = false } +sp1-primitives = { path = "crates/primitives", version = "1.2.0-rc1" } +sp1-prover = { path = "crates/prover", version = "1.2.0-rc1" } +sp1-recursion-compiler = { path = "crates/recursion/compiler", version = "1.2.0-rc1" } +sp1-recursion-core = { path = "crates/recursion/core", version = "1.2.0-rc1", default-features = false } +sp1-recursion-core-v2 = { path = "crates/recursion/core-v2", version = "1.2.0-rc1", default-features = false } +sp1-recursion-derive = { path = "crates/recursion/derive", version = "1.2.0-rc1", default-features = false } +sp1-recursion-gnark-ffi = { path = "crates/recursion/gnark-ffi", version = "1.2.0-rc1", default-features = false } +sp1-recursion-program = { path = "crates/recursion/program", version = "1.2.0-rc1", default-features = false } +sp1-recursion-circuit = { path = "crates/recursion/circuit", version = "1.2.0-rc1", default-features = false } +sp1-sdk = { path = "crates/sdk", version = "1.2.0-rc1" } +sp1-cuda = { path = "crates/cuda", version = "1.2.0-rc1" } +sp1-stark = { path = "crates/stark", version = "1.2.0-rc1" } +sp1-lib = { path = "crates/zkvm/lib", version = "1.2.0-rc1", default-features = false } +sp1-zkvm = { path = "crates/zkvm/entrypoint", version = "1.2.0-rc1", default-features = false } + +# p3 p3-air = "0.1.3-succinct" p3-field = "0.1.3-succinct" p3-commit = "0.1.3-succinct" diff --git a/Dockerfile.gnark-ffi b/Dockerfile.gnark-ffi index 6d7ab65ce0..49a53ab94a 100644 --- a/Dockerfile.gnark-ffi +++ b/Dockerfile.gnark-ffi @@ -19,11 +19,11 @@ RUN rustup show COPY . /sp1 # Build the gnark-ffi CLI -WORKDIR /sp1/recursion/gnark-cli +WORKDIR /sp1/crates/recursion/gnark-cli RUN \ --mount=type=cache,target=target \ - cargo build --release && cp ../../target/release/sp1-recursion-gnark-cli /gnark-cli + cargo build --release && cp ../../../target/release/sp1-recursion-gnark-cli /gnark-cli FROM rustlang/rust:nightly-bullseye-slim COPY --from=rust-builder /gnark-cli /gnark-cli diff --git a/book/SUMMARY.md b/book/SUMMARY.md index ba86732689..553a35a415 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -46,11 +46,15 @@ - [Recommended Workflow](./generating-proofs/recommended-workflow.md) - [Prover Network Beta](./generating-proofs/prover-network.md) + - [Key Setup](./generating-proofs/prover-network/key-setup.md) - [Usage](./generating-proofs/prover-network/usage.md) - [Supported Versions](./generating-proofs/prover-network/versions.md) -- [FAQ](./generating-proofs/sp1-sdk-faq.md) +- [Hardware Acceleration](./generating-proofs/hardware-acceleration.md) + - [AVX](./generating-proofs/hardware-acceleration/avx.md) + - [CUDA](./generating-proofs/hardware-acceleration/cuda.md) +- [FAQ](./generating-proofs/sp1-sdk-faq.md) # Onchain Verification diff --git a/book/developers/building-plonk-artifacts.md b/book/developers/building-plonk-artifacts.md index fd0ba2a68b..8f7eb5ad16 100644 --- a/book/developers/building-plonk-artifacts.md +++ b/book/developers/building-plonk-artifacts.md @@ -1,8 +1,8 @@ -# Building PLONK Artifacts +# Building Circuit Artifacts -To build the production Plonk Bn254 artifacts from scratch, you can use the `Makefile` inside the `prover` directory. +To build the production PLONK and Groth16 Bn254 artifacts from scratch, you can use the `Makefile` inside the `prover` directory. ```shell,noplayground cd prover -RUST_LOG=info make build-plonk-bn254 -``` \ No newline at end of file +RUST_LOG=info make build-circuits +``` diff --git a/book/developers/common-issues.md b/book/developers/common-issues.md index e88d099483..06556b82dd 100644 --- a/book/developers/common-issues.md +++ b/book/developers/common-issues.md @@ -29,18 +29,18 @@ This will configure out the `network` feature which will remove the dependency o ## Rust Version Errors -If you are using `alloy` or another library that has an MSRV (minimum supported rust version) of 1.76.0 +If you are using a library that has an MSRV (minimum supported rust version) of 1.76.0 or higher, you may encounter an error like this when building your program. ```txt package `alloy v0.1.1 cannot be built because it requires rustc 1.76 or newer, while the currently active rustc version is 1.75.0-nightly` ``` -This is due to the fact that the Succinct Rust toolchain might be built with a lower version than the MSRV of the crates you are using. You can check the version of the Succinct Rust toolchain by running `cargo +succinct --version`. If we have released a more recent version of the Succinct Rust toolchain, you can update it by running `sp1up` again to update the toolchain and CLI to the latest version. +This is due to the fact that the Succinct Rust toolchain might be built with a lower version than the MSRV of the crates you are using. You can check the version of the Succinct Rust toolchain by running `cargo +succinct --version`. The Succinct Rust toolchain's latest version is 1.79, and you can update to the latest version by running [`sp1up`](../getting-started/install.md). -You can also fix this issue with the following: +If that doesn't work (i.e. the MSRV of the crates you are using is still higher than the version of the Succinct Rust toolchain), you can try the following: -- If using `cargo prove build` directly, pass the `--ignore-rust-version` flag: +- If you're using `cargo prove build` directly, pass the `--ignore-rust-version` flag: ```bash cargo prove build --ignore-rust-version @@ -99,3 +99,23 @@ C++ toolchain be setting this variable manually: ```bash export CC_riscv32im_succinct_zkvm_elf=/path/to/toolchain ``` + +## Compilation Errors with [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-lib/latest/sp1_lib/fn.syscall_verify_sp1_proof.html) + +If you are using the [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-lib/latest/sp1_lib/fn.syscall_verify_sp1_proof.html) function, you may encounter compilation errors when building your program. + +```bash + [sp1] = note: rust-lld: error: undefined symbol: syscall_verify_sp1_proof + [sp1] >>> referenced by sp1_lib.b593533d149f0f6e-cgu.0 + [sp1] >>> sp1_lib-8f5deb4c47d01871.sp1_lib.b593533d149f0f6e-cgu.0.rcgu.o:(sp1_lib::verify::verify_sp1_proof::h5c1bb38f11b3fe71) in ... + [sp1] + [sp1] + [sp1] error: could not compile `package-name` (bin "package-name") due to 1 previous error + ``` + + To resolve this, ensure that you're importing both `sp1-lib` and `sp1-zkvm` with the verify feature enabled. + ```toml + [dependencies] + sp1-lib = { version = "", features = ["verify"] } + sp1-zkvm = { version = "", features = ["verify"] } + ``` \ No newline at end of file diff --git a/book/generating-proofs/hardware-acceleration.md b/book/generating-proofs/hardware-acceleration.md new file mode 100644 index 0000000000..766c9db4ed --- /dev/null +++ b/book/generating-proofs/hardware-acceleration.md @@ -0,0 +1,7 @@ +# Hardware Acceleration + +SP1 supports hardware acceleration on the following platforms: +- [AVX256/AVX512](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions) on x86 CPUs +- [CUDA](https://en.wikipedia.org/wiki/CUDA) on Nvidia GPUs + +To enable hardware acceleration, please refer to the platform specific instructions available in this section. \ No newline at end of file diff --git a/book/generating-proofs/hardware-acceleration/avx.md b/book/generating-proofs/hardware-acceleration/avx.md new file mode 100644 index 0000000000..e9fe8007bf --- /dev/null +++ b/book/generating-proofs/hardware-acceleration/avx.md @@ -0,0 +1,30 @@ +# AVX + +SP1 supports both AVX256 and AVX512 acceleration on x86 CPUs due to support in [Plonky3](https://github.com/Plonky3/Plonky3). +Whenever possible, we recommend using AVX512 acceleration as it provides better performance. + +## Checking for AVX + +To check if your CPU supports AVX, you can run the following command: + +`grep avx /proc/cpuinfo` + +Look for the flags `avx2` and `avx512`. + +## Enabling AVX256 + +To enable AVX256 acceleration, you can set the `RUSTFLAGS` environment variable to include the following flags: + +```bash +RUSTFLAGS="-C target-cpu=native" cargo run --release +``` + +## Enabling AVX512 + +To enable AVX512 acceleration, you can set the `RUSTFLAGS` environment variable to include the following flags: + +```bash +RUSTFLAGS="-C target-cpu=native -C target-feature=+avx512f" cargo run --release +``` + +Note that the `+avx512f` flag is required to enable AVX512 acceleration. \ No newline at end of file diff --git a/book/generating-proofs/hardware-acceleration/cuda.md b/book/generating-proofs/hardware-acceleration/cuda.md new file mode 100644 index 0000000000..e27d0ce9ac --- /dev/null +++ b/book/generating-proofs/hardware-acceleration/cuda.md @@ -0,0 +1,26 @@ +# CUDA + +
+WARNING: CUDA proving is still an experimental feature and may be buggy. +
+ + +SP1 supports CUDA acceleration, which can provide dramatically better latency and cost performance +compared to using the CPU prover, even with AVX acceleration. + +## Software Requirements + +Please make sure you have the following installed before using the CUDA prover: + +- [CUDA 12](https://developer.nvidia.com/cuda-12-0-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_local) +- [CUDA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) + +## Hardware Requirements + +- **CPU**: We recommend having at least 8 CPU cores with 32GB of RAM available to fully utilize the GPU. +- **GPU**: 24GB or more for core/compressed proofs, 40GB or more for shrink/wrap proofs + +## Usage + +To use the CUDA prover, you can compile the `sp1-sdk` crate with the `cuda` feature enabled. You +can use the normal methods on the `ProverClient` to generate proofs. \ No newline at end of file diff --git a/book/generating-proofs/proof-types.md b/book/generating-proofs/proof-types.md index 717b9b9510..70513f8faa 100644 --- a/book/generating-proofs/proof-types.md +++ b/book/generating-proofs/proof-types.md @@ -29,7 +29,7 @@ client.prove(&pk, stdin).compressed().run().unwrap(); ## PLONK
-WARNING: The PLONK prover requires around 128GB of RAM and is only guaranteed to work on official releases of SP1. We recommend using the prover network to generate PLONK proofs. +WARNING: The PLONK prover requires around 64GB of RAM and is only guaranteed to work on official releases of SP1. We recommend using the prover network to generate PLONK proofs.
diff --git a/book/generating-proofs/prover-network.md b/book/generating-proofs/prover-network.md index 54943b5410..593a9f41aa 100644 --- a/book/generating-proofs/prover-network.md +++ b/book/generating-proofs/prover-network.md @@ -2,52 +2,7 @@ > **Currently, the supported version of SP1 on the prover network is `v1.1.0`.** -So far we've explored how to generate proofs locally, but this can actually be inconvenient on local machines due to high memory / CPU requirements, especially for very large programs. - Succinct [has been building](https://blog.succinct.xyz/succinct-network/) the Succinct Prover Network, a distributed network of provers that can generate proofs of any size quickly and reliably. It's currently in private beta, but you can get access by following the steps below. -## Get your key whitelisted - -**[FILL OUT THIS FORM](https://forms.gle/rTUvhstS8PFfv9B3A)** to gain access to the Succinct -Network. Completing this form requires you to complete the [key setup](#key-setup) steps below. - -## Key Setup - -The prover network uses Secp256k1 keypairs for authentication, similar to Ethereum wallets. You may generate a new keypair explicitly for use with the prover network, or use an existing keypair. **You do not need to hold any funds in this account, it is used solely for access control.** - -After you have your whitelisted key, read the [Usage](./prover-network/usage.md) section to learn how to use it. - -### Generate a new keypair with `cast` - -Prover network keypair credentials can be generated using the -[cast](https://book.getfoundry.sh/cast/) CLI tool. - -First install [Foundry](https://book.getfoundry.sh/getting-started/installation#using-foundryup): - -```sh -curl -L https://foundry.paradigm.xyz | bash -``` - -Upon running this command, you will be prompted to source your shell profile and run `foundryup`. Afterwards you should have access to the `cast` command. - -Use `cast` to generate a new keypair: - -```sh -cast wallet new -``` - -which will give you an output similar to this: - -![Screenshot from running 'cast wallet new' to generate an SP1_PRIVATE_KEY.](./prover-network/key.png) - -The "Address" what you should submit in the [form](https://forms.gle/rTUvhstS8PFfv9B3A), in the example above this is `0x552f0FC6D736ed965CE07a3D71aA639De15B627b`. The "Private key" should be kept safe and -secure. When interacting with the network, you will set your `SP1_PRIVATE_KEY` environment variable -to this value. - -### Retrieve an existing key - -If you already have an existing key you would like to use, you can also use `cast` retrieve your address: - -```sh -cast wallet address --private-key $PRIVATE_KEY -``` +To get started, **[FILL OUT THIS FORM](https://forms.gle/rTUvhstS8PFfv9B3A)** to gain access to the Succinct +Network. Completing this form requires you to complete the [key setup](./prover-network/key-setup.md) steps below. \ No newline at end of file diff --git a/book/generating-proofs/prover-network/key-setup.md b/book/generating-proofs/prover-network/key-setup.md new file mode 100644 index 0000000000..222fba840f --- /dev/null +++ b/book/generating-proofs/prover-network/key-setup.md @@ -0,0 +1,40 @@ +# Prover Network: Key Setup + +The prover network uses Secp256k1 keypairs for authentication, similar to Ethereum wallets. You may generate a new keypair explicitly for use with the prover network, or use an existing keypair. + +> **You do not need to hold any funds in this account, it is used solely for access control.** + +### Generate a Public Key + +Prover network keypair credentials can be generated using the +[cast](https://book.getfoundry.sh/cast/) CLI tool. + +First install [Foundry](https://book.getfoundry.sh/getting-started/installation#using-foundryup): + +```sh +curl -L https://foundry.paradigm.xyz | bash +``` + +Upon running this command, you will be prompted to source your shell profile and run `foundryup`. Afterwards you should have access to the `cast` command. + +Use `cast` to generate a new keypair: + +```sh +cast wallet new +``` + +which will give you an output similar to this: + +![Screenshot from running 'cast wallet new' to generate an SP1_PRIVATE_KEY.](../prover-network/key.png) + +The "Address" what you should submit in the [form](https://forms.gle/rTUvhstS8PFfv9B3A), in the example above this is `0x552f0FC6D736ed965CE07a3D71aA639De15B627b`. The "Private key" should be kept safe and +secure. When interacting with the network, you will set your `SP1_PRIVATE_KEY` environment variable +to this value. + +### Retrieve an Existing Key + +If you already have an existing key you would like to use, you can also use `cast` retrieve your address: + +```sh +cast wallet address --private-key $PRIVATE_KEY +``` diff --git a/book/generating-proofs/prover-network/versions.md b/book/generating-proofs/prover-network/versions.md index bf00ee83c3..633fbe6e24 100644 --- a/book/generating-proofs/prover-network/versions.md +++ b/book/generating-proofs/prover-network/versions.md @@ -4,7 +4,9 @@ The prover network currently only supports specific versions of SP1: | Environment | RPC URL | Supported Version | | ----------- | -------------------------- | ----------------- | -| Prod | `https://rpc.succinct.xyz` | v1.1.0 | +| Production | `https://rpc.succinct.xyz` | `v1.2.X` | + +Where `X` denotes that any patch version is supported (e.g. `v1.2.0`, `v1.2.1`). If you submit a proof request to the prover network and your are not using the supported version, you will receive an error message. diff --git a/book/generating-proofs/sp1-sdk-faq.md b/book/generating-proofs/sp1-sdk-faq.md index fcfdfe678e..76e62d81e4 100644 --- a/book/generating-proofs/sp1-sdk-faq.md +++ b/book/generating-proofs/sp1-sdk-faq.md @@ -12,23 +12,4 @@ Example of setting the logging level to `info` (other options are `debug`, `trac ```bash RUST_LOG=info cargo run --release -``` - - -## Optimize Local Proving with CPU Acceleration - -SP1 supports CPU hardware acceleration using AVX256/512 and NEON SIMD instructions. To enable the acceleration, you can use the `RUSTFLAGS` environment variable to generate code that is optimized for your CPU. - -**AVX2 / NEON**: -```bash -RUSTFLAGS='-C target-cpu=native' cargo run --release -``` - -**AVX512**: -```bash -RUSTFLAGS='-C target-cpu=native -C target_feature=+avx512ifma,+avx512vl' cargo run --release -``` - -## GPU Proving - -Note that SP1 has a GPU prover that is currently in beta, but it is not yet supported in the `sp1-sdk` crate and has experimental support in the `sp1-prover` crate. Our prover network currently runs the SP1 GPU prover, so the recommended way to generate proofs with GPU is via the prover network. \ No newline at end of file +``` \ No newline at end of file diff --git a/book/getting-started/hardware-requirements.md b/book/getting-started/hardware-requirements.md index bd31825fe3..b567f897ab 100644 --- a/book/getting-started/hardware-requirements.md +++ b/book/getting-started/hardware-requirements.md @@ -1,21 +1,21 @@ # Proof Generation Requirements -## Prover Network (Recommended) - -We recommend that developers who want to use SP1 for non-trivial programs generate proofs on our [Prover Network's](../generating-proofs/prover-network.md) private beta. The prover network generates SP1 proofs across multiple machines, reducing latency and also runs SP1 on optimized hardware instances that result in faster + cheaper proof generation times (including SP1's GPU prover that is not yet available for local proving). +
+We recommend that developers who want to use SP1 for non-trivial programs generate proofs on our prover network. The prover network generates SP1 proofs across multiple machines, reducing latency and also runs SP1 on optimized hardware instances that result in faster + cheaper proof generation times. We recommend that for any production benchmarking, you use the prover network to estimate latency and costs of proof generation. +
## Local Proving -If you want to generate SP1 proofs locally, here is an overview of the hardware requirements required. These requires depend on which [types of proofs](../generating-proofs/proof-types.md) you want to generate and can also change over time as the design of the zKVM evolves. +If you want to generate SP1 proofs locally, this section has an overview of the hardware requirements required. These requires depend on which [types of proofs](../generating-proofs/proof-types.md) you want to generate and can also change over time as the design of the zKVM evolves. **The most important requirement is CPU for performance/latency and RAM to prevent running out of memory.** | | Mock / Network | Core / Compress | PLONK (EVM) | |----------------|------------------------------|------------------------------------|----------------------------| | CPU | 1+, single-core perf matters | 16+, more is better | 32+, more is better | -| Memory | 8GB+, more is better | 32GB+, more if you have more cores | 128GB+ (for PLONK) | +| Memory | 8GB+, more is better | 32GB+, more if you have more cores | 64GB+ (for PLONK) | | Disk | 20GB+ | 20GB+ | 100GB+ (for trusted setup) | | EVM Compatible | ✅ | ❌ | ✅ | diff --git a/book/getting-started/install.md b/book/getting-started/install.md index dbb91c7899..e58b9a624e 100644 --- a/book/getting-started/install.md +++ b/book/getting-started/install.md @@ -11,7 +11,7 @@ build the Succinct [Rust toolchain](https://rust-lang.github.io/rustup/concepts/ ## Option 1: Prebuilt Binaries (Recommended) -sp1up is the SP1 toolchain installer. Open your terminal and run the following command and follow the instructions: +`sp1up` is the SP1 toolchain installer. Open your terminal and run the following command and follow the instructions: ```bash curl -L https://sp1.succinct.xyz | bash @@ -89,6 +89,7 @@ Clone the `sp1` repository and navigate to the root directory. ```bash git clone git@github.com:succinctlabs/sp1.git cd sp1 +cd crates cd cli cargo install --locked --path . cd ~ diff --git a/book/getting-started/quickstart.md b/book/getting-started/quickstart.md index 2abd480541..02b0f1a3f2 100644 --- a/book/getting-started/quickstart.md +++ b/book/getting-started/quickstart.md @@ -23,7 +23,7 @@ Either fork the project template repository or clone it: git clone https://github.com/succinctlabs/sp1-project-template.git ``` -## Project Overview +### Project Overview Your new project will have the following structure (ignoring the `contracts` folder, if you are using the project template): @@ -53,27 +53,33 @@ There are 2 directories (each a crate) in the project: - `program`: the source code that will be proven inside the zkVM. - `script`: code that contains proof generation and verification code. -We recommend you install the [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) extension. +**We recommend you install the [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) extension.** Note that if you use `cargo prove new` inside a monorepo, you will need to add the manifest file to `rust-analyzer.linkedProjects` to get full IDE support. -## Generate Proofs +## Build -The program in the starter examplesimply computes the `n`-th Fibonacci number. +Before we can run the program inside the zkVM, it must be compiled to a RISC-V executable using the `succinct` Rust toolchain. This is called an [ELF (Executable and Linkable Format)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format). To compile the program, you can run the following command: -Before we can run the program inside the zkVM, it must be compiled to a RISC-V executable using the `succinct` Rust toolchain. This is called an [ELF (Executable and Linkable Format)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format). To compile the program, you can run `cd program && cargo prove build`, which will output the compiled ELF to the file `program/elf/riscv32im-succinct-zkvm-elf`. +``` +cd program && cargo prove build +``` + +which will output the compiled ELF to the file `program/elf/riscv32im-succinct-zkvm-elf`. -In our case, the `build.rs` file in the `script` directory will use run the above command automatically to build the ELF, meaning you don't have to manually run `cargo prove build` every time you make a change to the program. +Note: the `build.rs` file in the `script` directory will use run the above command automatically to build the ELF, meaning you don't have to manually run `cargo prove build` every time you make a change to the program! -To generate a proof, we take the ELF file generated by the `build.rs` file and execute it within the SP1 zkVM. The code in the `script` directory is already scaffolded with a script that has logic to generate a proof, save the proof to disk, and verify it. +## Execute -First, you should run the script with the `--execute` flag to *only execute* your program (without generating a proof). In general this is helpful for iterating on your program and verifying that it is correct. +To test your program, you can first execute your program without generating a proof. In general this is helpful for iterating on your program and verifying that it is correct. ```bash cd script RUST_LOG=info cargo run --release -- --execute ``` -Next, you should run the script with the `--prove` flag that will generate a proof and save it to disk. Please go to the [Recommended Workflow](../generating-proofs/recommended-workflow.md) section for more details on how you should develop your SP1 program and generate proofs. +## Prove + +When you are ready to generate a proof, you should run the script with the `--prove` flag that will generate a proof. ```bash cd script @@ -106,15 +112,6 @@ The program by default is quite small, so proof generation will only take a few **Note:** When benchmarking proof generation times locally, it is important to note that there is a fixed overhead for proving, which means that the proof generation time for programs with a small number of cycles is not representative of the performance of larger programs (which often have better performance characteristics as the overhead is amortized across many cycles). -**Modifying the Program** - -You can play around with how many rounds of Fibonacci are executed by playing around with `n` (by default set to `20`) in the file `script/src/main.rs`. - -The ELF will be automatically rebuilt every time you modify the program. You can verify that the ELF was re-generated by looking in the `elf` directory and for a file called `riscv32im-succinct-zkvm-elf`: -```bash -ls elf # should show riscv32im-succinct-zkvm-elf -``` - ## Recommended Workflow Please see the [Recommended Workflow](../generating-proofs/recommended-workflow.md) section for more details on how to develop your SP1 program and generate proofs. diff --git a/book/writing-programs/compiling.md b/book/writing-programs/compiling.md index e40a189d3c..29a33cedd7 100644 --- a/book/writing-programs/compiling.md +++ b/book/writing-programs/compiling.md @@ -2,7 +2,7 @@ Once you have written an SP1 program, you must compile it to an ELF file that can be executed in the zkVM. The `cargo prove` CLI tool (downloaded during installation) provides convenient commands for compiling SP1 programs. -## Compile with CLI (Development) +## Development Builds > WARNING: This may not generate a reproducible ELF which is necessary for verifying that your binary corresponds to given source code. > @@ -30,12 +30,12 @@ This will compile the ELF that can be executed in the zkVM and put it in the fil Under the hood, this CLI command calls `cargo build` with the `riscv32im-succinct-zkvm-elf` target and other required environment variables and flags. The logic for this command is defined in the [sp1-build](https://github.com/succinctlabs/sp1/tree/main/build) crate. -### Advanced build options +### Advanced Build Options You can pass additional arguments to the `cargo prove build` command to customize the build process, like configuring what features are enabled, customizing the output directory and more. To see all available options, run `cargo prove build --help`. Many of these options mirror the options available in the `cargo build` command. -## Reproducible Builds with Docker (Production) +## Production Builds For production builds of programs, you can build your program inside a Docker container which will generate a **reproducible ELF** on all platforms. To do so, just use the `--docker` flag and optionally the `--tag` flag with the release version you want to use (defaults to `latest`). For example: @@ -52,17 +52,17 @@ f9afb8caaef10de9a8aad484c4dd3bfa54ba7218f3fc245a20e8a03ed40b38c617e175328515968a ## Build Script -If you want your program crate to be built automatically whenever you build/run your script crate, you can add a `build.rs` file inside of `script/` (at the same level as `Cargo.toml` of your script crate) that utilizes the `sp1-helper` crate: +If you want your program crate to be built automatically whenever you build/run your script crate, you can add a `build.rs` file inside of `script/` (at the same level as `Cargo.toml` of your script crate) that utilizes the `sp1-build` crate: ```rust,noplayground {{#include ../../examples/fibonacci/script/build.rs}} ``` -The path passed in to `build_program` should point to the directory containing the `Cargo.toml` file for your program. Make sure to also add `sp1-helper` as a build dependency in `script/Cargo.toml`: +The path passed in to `build_program` should point to the directory containing the `Cargo.toml` file for your program. Make sure to also add `sp1-build` as a build dependency in `script/Cargo.toml`: ```toml [build-dependencies] -sp1-helper = "1.1.0" +sp1-build = "1.2.0" ``` You will see output like the following from the build script if the program has changed, indicating that the program was rebuilt: @@ -80,14 +80,14 @@ warning: fibonacci-script@0.1.0: fibonacci-program built at 2024-03-02 22:01:26 The above output was generated by running `RUST_LOG=info cargo run --release -vv` for the `script` folder of the Fibonacci example. -### Advanced build options +### Advanced Build Options -To configure the build process when using the `sp1-helper` crate, you can pass a [`BuildArgs`](https://docs.rs/sp1-helper/1.1.0/sp1_helper/struct.BuildArgs.html) struct to to the [`build_program_with_args`](https://docs.rs/sp1-helper/1.1.0/sp1_helper/fn.build_program_with_args.html) function. The build arguments are the same as the ones available from the `cargo prove build` command. +To configure the build process when using the `sp1-build` crate, you can pass a [`BuildArgs`](https://docs.rs/sp1-build/1.2.0/sp1_build/struct.BuildArgs.html) struct to to the [`build_program_with_args`](https://docs.rs/sp1-build/1.2.0/sp1_build/fn.build_program_with_args.html) function. The build arguments are the same as the ones available from the `cargo prove build` command. As an example, you could use the following code to build the Fibonacci example with the `docker` flag set to `true` and a custom output directory for the generated ELF: ```rust,noplayground -use sp1_helper::{build_program_with_args, BuildArgs}; +use sp1_build::{build_program_with_args, BuildArgs}; fn main() { let args = BuildArgs { diff --git a/book/writing-programs/cycle-tracking.md b/book/writing-programs/cycle-tracking.md index 171a36d3ff..176249b45e 100644 --- a/book/writing-programs/cycle-tracking.md +++ b/book/writing-programs/cycle-tracking.md @@ -7,7 +7,7 @@ When writing a program, it is useful to know how many RISC-V cycles a portion of To track the number of cycles spent in a portion of the program, you can either put `println!("cycle-tracker-start: block name")` + `println!("cycle-tracker-end: block name")` statements (block name must be same between start and end) around the portion of your program you want to profile or use the `#[sp1_derive::cycle_tracker]` macro on a function. An example is shown below: ```rust,noplayground -{{#include ../../examples/cycle-tracking/program/src/main.rs}} +{{#include ../../examples/cycle-tracking/program/bin/normal.rs}} ``` Note that to use the macro, you must add the `sp1-derive` crate to your dependencies for your program. @@ -42,6 +42,19 @@ stdout: result: 2940 Note that we elegantly handle nested cycle tracking, as you can see above. +### Get Tracked Cycle Counts +To include tracked cycle counts in the `ExecutionReport` when using `ProverClient::execute`, use the following annotations: + +```rust,noplayground +fn main() { + println!("cycle-tracker-report-start: block name"); + // ... + println!("cycle-tracker-report-end: block name"); +} +``` + +This will log the cycle count for `block name` and include it in the `ExecutionReport` in the `cycle_tracker` map. + ## Tracking Cycles with Tracing The `cycle-tracker` annotation is a convenient way to track cycles for specific sections of code. However, sometimes it can also be useful to track what functions are taking the most cycles across the entire program, without having to annotate every function individually. diff --git a/book/writing-programs/patched-crates.md b/book/writing-programs/patched-crates.md index b44188d122..4f9ff7f727 100644 --- a/book/writing-programs/patched-crates.md +++ b/book/writing-programs/patched-crates.md @@ -7,17 +7,19 @@ Under the hood, we use [precompiles](./precompiles.md) to achieve tremendous per ## Supported Libraries -| Crate Name | Repository | Notes | -| ------------------- | ------------------------------------------------------------------------------------- | ---------------- | -| sha2 | [sp1-patches/RustCrypto-hashes](https://github.com/sp1-patches/RustCrypto-hashes) | sha256 | -| sha3 | [sp1-patches/RustCrypto-hashes](https://github.com/sp1-patches/RustCrypto-hashes) | keccak256 | -| bigint | [sp1-patches/RustCrypto-bigint](https://github.com/sp1-patches/RustCrypto-bigint) | bigint | -| tiny-keccak | [sp1-patches/tiny-keccak](https://github.com/sp1-patches/tiny-keccak) | keccak256 | -| ed25519-consensus | [sp1-patches/ed25519-consensus](http://github.com/sp1-patches/ed25519-consensus) | ed25519 verify | -| curve25519-dalek-ng | [sp1-patches/curve25519-dalek-ng](https://github.com/sp1-patches/curve25519-dalek-ng) | ed25519 verify | -| curve25519-dalek | [sp1-patches/curve25519-dalek](https://github.com/sp1-patches/curve25519-dalek) | ed25519 verify | -| ecdsa-core | [sp1-patches/signatures](http://github.com/sp1-patches/signatures) | secp256k1 verify | -| secp256k1 | [sp1-patches/rust-secp256k1](http://github.com/sp1-patches/rust-secp256k1) | secp256k1 verify | +| Crate Name | Repository | Notes | +| ------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------- | +| sha2 | [sp1-patches/RustCrypto-hashes](https://github.com/sp1-patches/RustCrypto-hashes) | sha256 | +| sha3 | [sp1-patches/RustCrypto-hashes](https://github.com/sp1-patches/RustCrypto-hashes) | keccak256 | +| bigint | [sp1-patches/RustCrypto-bigint](https://github.com/sp1-patches/RustCrypto-bigint) | bigint | +| tiny-keccak | [sp1-patches/tiny-keccak](https://github.com/sp1-patches/tiny-keccak) | keccak256 | +| ed25519-consensus | [sp1-patches/ed25519-consensus](http://github.com/sp1-patches/ed25519-consensus) | ed25519 verify | +| curve25519-dalek-ng | [sp1-patches/curve25519-dalek-ng](https://github.com/sp1-patches/curve25519-dalek-ng) | ed25519 verify | +| curve25519-dalek | [sp1-patches/curve25519-dalek](https://github.com/sp1-patches/curve25519-dalek) | ed25519 verify | +| ecdsa-core | [sp1-patches/signatures](http://github.com/sp1-patches/signatures) | secp256k1 verify | +| secp256k1 | [sp1-patches/rust-secp256k1](http://github.com/sp1-patches/rust-secp256k1) | secp256k1 verify | +| **** | substrate-bn | [sp1-patches/bn](https://github.com/sp1-patches/bn) | BN254 | +| substrate-bls12_381 | [sp1-patches/bls12_381](https://github.com/sp1-patches/bls12_381) | bls12_381 | ## Using Patched Crates @@ -37,7 +39,10 @@ curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", br curve25519-dalek-ng = { git = "https://github.com/sp1-patches/curve25519-dalek-ng", branch = "patch-v4.1.1" } ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", branch = "patch-v2.1.0" } ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "patch-ecdsa-v0.16.9" } -secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-v0.29.0" } +secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.0" } +substrate-bn = { git = "https://github.com/sp1-patches/bn", branch = "patch-v0.6.0" } +bls12_381 = { git = "https://github.com/sp1-patches/bls12_381", branch = "patch-v0.8.8" } + ``` If you are patching a crate from Github instead of from crates.io, you need to specify the @@ -106,6 +111,47 @@ Apply the following patches based on what crates are in your dependencies. secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-v0.29.0" } ``` +## BN254 Acceleration +To accelerate BN254 (Also known as BN128 and Alt-BN128), you will need to patch the `substrate-bn` crate. + +### Patches + +Apply the patch by adding the following to your list of dependencies: +```rust +substrate-bn = { git = "https://github.com/sp1-patches/bn", branch = "patch-v0.6.0" } +``` + +### Performance Benchmarks for Patched `substrate-bn` in `revm` + +| Operation | Standard `substrate-bn` Cycles | Patched `substrate-bn` Cycles | Times Faster | +| --------- | ------------------------------ | ----------------------------- | ------------ | +| run-add | 170,298 | 111,615 | 1.52 | +| run-mul | 1,860,836 | 243,830 | 7.64 | +| run-pair | 255,627,625 | 11,528,503 | 22.15 | + +Note: The operations `run-add`, `run-mul`, and `run-pair` are from the `revm` crate, specifically from the file `crates/precompile/src/bn128.rs` on GitHub. In the patched version of the `substrate-bn` crate, these functions utilize SP1's BN254 Fp precompiles. + +To accelerate [revm](https://github.com/bluealloy/revm) in SP1 using the BN254 patched crate, replace the `substrate-bn` crate with the patched crate by adding the following to `crates/precompile/Cargo.toml`: +```rust +bn = { git = "https://github.com/sp1-patches/bn", package = "substrate-bn", branch = "patch-v0.6.0" } +``` + +## BLS12-381 Acceleration +To accelerate BLS12-381 operations, you'll need to patch the `bls12_381` crate. Apply the following patch by adding the following to your list of dependencies: +```toml +blst = { git = "https://github.com/sp1-patches/bls12_381", branch = "patch-v0.8.0" } +``` +This patch significantly improves the performance of BLS12-381 operations, making it essential for applications that rely heavily on these cryptographic primitives. + +### Performance Benchmarks for Patched `bls12_381` in [`kzg-rs`](https://github.com/succinctlabs/kzg-rs) +| Test | Unpatched Cycles | Patched Cycles | Improvement (x faster) | +| -------------------------------------- | ---------------- | -------------- | ---------------------- | +| Verify blob KZG proof | 265,322,934 | 27,166,173 | 9.77x | +| Verify blob KZG proof batch (10 blobs) | 1,228,277,089 | 196,571,578 | 6.25x | +| Evaluate polynomial in evaluation form | 90,717,711 | 59,370,556 | 1.53x | +| Compute challenge | 63,400,511 | 57,341,532 | 1.11x | +| Verify KZG proof | 212,708,597 | 9,390,640 | 22.65x | + ## Troubleshooting ### Verifying Patch Usage: Cargo diff --git a/build/src/lib.rs b/build/src/lib.rs deleted file mode 100644 index 56de3ad217..0000000000 --- a/build/src/lib.rs +++ /dev/null @@ -1,304 +0,0 @@ -mod docker; - -use anyhow::{Context, Result}; -use cargo_metadata::camino::Utf8PathBuf; -use clap::Parser; -use dirs::home_dir; -use std::{ - env, fs, - io::{BufRead, BufReader}, - path::PathBuf, - process::{exit, Command, Stdio}, - thread, -}; - -const BUILD_TARGET: &str = "riscv32im-succinct-zkvm-elf"; -const DEFAULT_TAG: &str = "v1.1.0"; -const DEFAULT_OUTPUT_DIR: &str = "elf"; -const HELPER_TARGET_SUBDIR: &str = "elf-compilation"; - -/// Compile an SP1 program. -/// -/// Additional arguments are useful for configuring the build process, including options for using Docker, -/// specifying binary and ELF names, ignoring Rust version checks, and enabling specific features. -#[derive(Clone, Parser, Debug)] -pub struct BuildArgs { - #[clap( - long, - action, - help = "Run compilation using a Docker container for reproducible builds." - )] - pub docker: bool, - #[clap( - long, - help = "The ghcr.io/succinctlabs/sp1 image tag to use when building with Docker.", - default_value = DEFAULT_TAG - )] - pub tag: String, - #[clap( - long, - action, - value_delimiter = ',', - help = "Space or comma separated list of features to activate" - )] - pub features: Vec, - #[clap(long, action, help = "Do not activate the `default` feature")] - pub no_default_features: bool, - #[clap(long, action, help = "Ignore `rust-version` specification in packages")] - pub ignore_rust_version: bool, - #[clap(long, action, help = "Assert that `Cargo.lock` will remain unchanged")] - pub locked: bool, - #[clap( - alias = "bin", - long, - action, - help = "Build only the specified binary", - default_value = "" - )] - pub binary: String, - #[clap(long, action, help = "ELF binary name", default_value = "")] - pub elf_name: String, - #[clap( - alias = "out-dir", - long, - action, - help = "Copy the compiled ELF to this directory", - default_value = DEFAULT_OUTPUT_DIR - )] - pub output_directory: String, -} - -// Implement default args to match clap defaults. -impl Default for BuildArgs { - fn default() -> Self { - Self { - docker: false, - tag: DEFAULT_TAG.to_string(), - features: vec![], - ignore_rust_version: false, - binary: "".to_string(), - elf_name: "".to_string(), - output_directory: DEFAULT_OUTPUT_DIR.to_string(), - locked: false, - no_default_features: false, - } - } -} - -/// Get the arguments to build the program with the arguments from the [`BuildArgs`] struct. -fn get_program_build_args(args: &BuildArgs) -> Vec { - let mut build_args = vec![ - "build".to_string(), - "--release".to_string(), - "--target".to_string(), - BUILD_TARGET.to_string(), - ]; - - if args.ignore_rust_version { - build_args.push("--ignore-rust-version".to_string()); - } - - if !args.binary.is_empty() { - build_args.push("--bin".to_string()); - build_args.push(args.binary.clone()); - } - - if !args.features.is_empty() { - build_args.push("--features".to_string()); - build_args.push(args.features.join(",")); - } - - if args.no_default_features { - build_args.push("--no-default-features".to_string()); - } - - if args.locked { - build_args.push("--locked".to_string()); - } - - build_args -} - -/// Rust flags for compilation of C libraries. -fn get_rust_compiler_flags() -> String { - let rust_flags = [ - "-C".to_string(), - "passes=loweratomic".to_string(), - "-C".to_string(), - "link-arg=-Ttext=0x00200800".to_string(), - "-C".to_string(), - "panic=abort".to_string(), - ]; - rust_flags.join("\x1f") -} - -/// Get the command to build the program locally. -fn create_local_command( - args: &BuildArgs, - program_dir: &Utf8PathBuf, - program_metadata: &cargo_metadata::Metadata, -) -> Command { - let mut command = Command::new("cargo"); - let canonicalized_program_dir = program_dir - .canonicalize() - .expect("Failed to canonicalize program directory"); - - // If CC_riscv32im_succinct_zkvm_elf is not set, set it to the default C++ toolchain - // downloaded by 'sp1up --c-toolchain'. - if env::var("CC_riscv32im_succinct_zkvm_elf").is_err() { - if let Some(home_dir) = home_dir() { - let cc_path = home_dir - .join(".sp1") - .join("bin") - .join("riscv32-unknown-elf-gcc"); - if cc_path.exists() { - command.env("CC_riscv32im_succinct_zkvm_elf", cc_path); - } - } - } - - // When executing the local command: - // 1. Set the target directory to a subdirectory of the program's target directory to avoid build - // conflicts with the parent process. Source: https://github.com/rust-lang/cargo/issues/6412 - // 2. Set the rustup toolchain to succinct. - // 3. Set the encoded rust flags. - // 4. Remove the rustc configuration, otherwise in a build script it will attempt to compile the - // program with the toolchain of the normal build process, rather than the Succinct toolchain. - command - .current_dir(canonicalized_program_dir) - .env("RUSTUP_TOOLCHAIN", "succinct") - .env("CARGO_ENCODED_RUSTFLAGS", get_rust_compiler_flags()) - .env_remove("RUSTC") - .env( - "CARGO_TARGET_DIR", - program_metadata.target_directory.join(HELPER_TARGET_SUBDIR), - ) - .args(&get_program_build_args(args)); - command -} - -/// Execute the command and handle the output depending on the context. -fn execute_command(mut command: Command, docker: bool) -> Result<()> { - // Add necessary tags for stdout and stderr from the command. - let mut child = command - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context("failed to spawn command")?; - let stdout = BufReader::new(child.stdout.take().unwrap()); - let stderr = BufReader::new(child.stderr.take().unwrap()); - - // Add prefix to the output of the process depending on the context. - let msg = match docker { - true => "[sp1] [docker] ", - false => "[sp1] ", - }; - - // Pipe stdout and stderr to the parent process with [docker] prefix - let stdout_handle = thread::spawn(move || { - stdout.lines().for_each(|line| { - println!("{} {}", msg, line.unwrap()); - }); - }); - stderr.lines().for_each(|line| { - eprintln!("{} {}", msg, line.unwrap()); - }); - stdout_handle.join().unwrap(); - - // Wait for the child process to finish and check the result. - let result = child.wait()?; - if !result.success() { - // Error message is already printed by cargo. - exit(result.code().unwrap_or(1)) - } - Ok(()) -} - -/// Copy the ELF to the specified output directory. -fn copy_elf_to_output_dir( - args: &BuildArgs, - program_metadata: &cargo_metadata::Metadata, -) -> Result { - let root_package = program_metadata.root_package(); - let root_package_name = root_package.as_ref().map(|p| &p.name); - - // The ELF is written to a target folder specified by the program's package. If built with Docker, - // includes /docker after HELPER_TARGET_SUBDIR. - let target_dir_suffix = if args.docker { - format!("{}/{}", HELPER_TARGET_SUBDIR, "docker") - } else { - HELPER_TARGET_SUBDIR.to_string() - }; - - let original_elf_path = program_metadata - .target_directory - .join(target_dir_suffix) - .join(BUILD_TARGET) - .join("release") - .join(root_package_name.unwrap()); - - // The order of precedence for the ELF name is: - // 1. --elf_name flag - // 2. --binary flag + -elf suffix (defaults to riscv32im-succinct-zkvm-elf) - let elf_name = if !args.elf_name.is_empty() { - args.elf_name.clone() - } else if !args.binary.is_empty() { - // TODO: In the future, change this to default to the package name. Will require updating - // docs and examples. - args.binary.clone() - } else { - BUILD_TARGET.to_string() - }; - - let elf_dir = program_metadata - .target_directory - .parent() - .unwrap() - .join(&args.output_directory); - fs::create_dir_all(&elf_dir)?; - let result_elf_path = elf_dir.join(elf_name); - - // Copy the ELF to the specified output directory. - fs::copy(original_elf_path, &result_elf_path)?; - - Ok(result_elf_path) -} - -/// Build a program with the specified [`BuildArgs`]. The `program_dir` is specified as an argument when -/// the program is built via `build_program` in sp1-helper. -/// -/// # Arguments -/// -/// * `args` - A reference to a `BuildArgs` struct that holds various arguments used for building the program. -/// * `program_dir` - An optional `PathBuf` specifying the directory of the program to be built. -/// -/// # Returns -/// -/// * `Result` - The path to the built program as a `Utf8PathBuf` on success, or an error on failure. -pub fn build_program(args: &BuildArgs, program_dir: Option) -> Result { - // If the program directory is not specified, use the current directory. - let program_dir = program_dir - .unwrap_or_else(|| std::env::current_dir().expect("Failed to get current directory.")); - let program_dir: Utf8PathBuf = program_dir - .try_into() - .expect("Failed to convert PathBuf to Utf8PathBuf"); - - // Get the program metadata. - let program_metadata_file = program_dir.join("Cargo.toml"); - let mut program_metadata_cmd = cargo_metadata::MetadataCommand::new(); - let program_metadata = program_metadata_cmd - .manifest_path(program_metadata_file) - .exec() - .unwrap(); - - // Get the command corresponding to Docker or local build. - let cmd = if args.docker { - docker::create_docker_command(args, &program_dir, &program_metadata)? - } else { - create_local_command(args, &program_dir, &program_metadata) - }; - - execute_command(cmd, args.docker)?; - - copy_elf_to_output_dir(args, &program_metadata) -} diff --git a/cli/build.rs b/cli/build.rs deleted file mode 100644 index 594550b4a7..0000000000 --- a/cli/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - vergen::EmitBuilder::builder() - .build_timestamp() - .git_sha(true) - .emit() - .unwrap(); -} diff --git a/cli/docker/Dockerfile b/cli/docker/Dockerfile deleted file mode 100644 index d08d001959..0000000000 --- a/cli/docker/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM ubuntu:24.04@sha256:e3f92abc0967a6c19d0dfa2d55838833e947b9d74edbcb0113e48535ad4be12a - -RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates clang curl libssl-dev pkg-config git dialog xz-utils \ - && curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL 'https://sh.rustup.rs' | sh -s -- -y - -ENV PATH="/root/.cargo/bin:${PATH}" - -ARG BUILDTIME - -# Use the BUILDTIME argument to break caching and force a new layer -RUN echo "Cache bust: ${BUILDTIME}" > /dev/null && \ - curl -L https://sp1.succinct.xyz | bash && ~/.sp1/bin/sp1up - -# Install the C++ toolchain for RISC-V and create a symlink to it in /root/.sp1/bin -RUN mkdir -p /root/.sp1/riscv \ - && curl -L https://github.com/risc0/toolchain/releases/download/2022.03.25/riscv32im-linux-x86_64.tar.xz -o /tmp/riscv32im-linux-x86_64.tar.xz \ - && tar -xvf /tmp/riscv32im-linux-x86_64.tar.xz -C /root/.sp1/riscv/ \ - && rm -f /tmp/riscv32im-linux-x86_64.tar.xz \ - && find /root/.sp1/riscv -name 'riscv32-unknown-elf-gcc' -type f -exec ln -sf {} /root/.sp1/bin/riscv32-unknown-elf-gcc \; - -# Add the C++ toolchain to the path and the CC environment variable -ENV PATH="/root/.sp1/bin:${PATH}" -ENV CC_riscv32im_succinct_zkvm_elf=/root/.sp1/bin/riscv32-unknown-elf-gcc - -WORKDIR /root/program - -ENV CARGO_TERM_COLOR=always -ENTRYPOINT [ "/root/.sp1/bin/cargo-prove" ] -CMD [ "prove" ] \ No newline at end of file diff --git a/core/benches/main.rs b/core/benches/main.rs deleted file mode 100644 index ff186cce11..0000000000 --- a/core/benches/main.rs +++ /dev/null @@ -1,38 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use sp1_core::io::SP1Stdin; -use sp1_core::runtime::{Program, Runtime}; -use sp1_core::stark::CpuProver; -use sp1_core::utils::{prove, BabyBearPoseidon2, SP1CoreOpts}; - -#[allow(unreachable_code)] -pub fn criterion_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("prove"); - group.sample_size(10); - let programs = ["fibonacci"]; - for p in programs { - let elf_path = format!("../programs/demo/{}/elf/riscv32im-succinct-zkvm-elf", p); - let program = Program::from_elf(&elf_path); - let cycles = { - let mut runtime = Runtime::new(program.clone(), SP1CoreOpts::default()); - runtime.run().unwrap(); - runtime.state.global_clk - }; - group.bench_function( - format!("main:{}:{}", p.split('/').last().unwrap(), cycles), - |b| { - b.iter(|| { - prove::<_, CpuProver<_, _>>( - black_box(program.clone()), - &SP1Stdin::new(), - BabyBearPoseidon2::new(), - SP1CoreOpts::default(), - ) - }) - }, - ); - } - group.finish(); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/core/src/air/builder.rs b/core/src/air/builder.rs deleted file mode 100644 index d5d87b2b23..0000000000 --- a/core/src/air/builder.rs +++ /dev/null @@ -1,742 +0,0 @@ -use std::array; -use std::iter::once; - -use itertools::Itertools; -use p3_air::{AirBuilder, FilteredAirBuilder}; -use p3_air::{AirBuilderWithPublicValues, PermutationAirBuilder}; -use p3_field::{AbstractField, Field}; -use p3_uni_stark::StarkGenericConfig; -use p3_uni_stark::{ProverConstraintFolder, SymbolicAirBuilder, VerifierConstraintFolder}; - -use super::interaction::AirInteraction; -use super::word::Word; -use super::{BinomialExtension, WORD_SIZE}; -use crate::cpu::columns::InstructionCols; -use crate::cpu::columns::OpcodeSelectorCols; -use crate::lookup::InteractionKind; -use crate::memory::MemoryAccessCols; -use crate::{bytes::ByteOpcode, memory::MemoryCols}; - -/// A Builder with the ability to encode the existance of interactions with other AIRs by sending -/// and receiving messages. -pub trait MessageBuilder { - fn send(&mut self, message: M); - - fn receive(&mut self, message: M); -} - -impl MessageBuilder for AB { - fn send(&mut self, _message: M) {} - - fn receive(&mut self, _message: M) {} -} - -/// A message builder for which sending and receiving messages is a no-op. -pub trait EmptyMessageBuilder: AirBuilder {} - -/// A trait which contains basic methods for building an AIR. -pub trait BaseAirBuilder: AirBuilder + MessageBuilder> { - /// Returns a sub-builder whose constraints are enforced only when `condition` is not one. - fn when_not>(&mut self, condition: I) -> FilteredAirBuilder { - self.when_ne(condition, Self::F::one()) - } - - /// Asserts that an iterator of expressions are all equal. - fn assert_all_eq, I2: Into>( - &mut self, - left: impl IntoIterator, - right: impl IntoIterator, - ) { - for (left, right) in left.into_iter().zip_eq(right) { - self.assert_eq(left, right); - } - } - - /// Asserts that an iterator of expressions are all zero. - fn assert_all_zero>(&mut self, iter: impl IntoIterator) { - iter.into_iter().for_each(|expr| self.assert_zero(expr)); - } - - /// Will return `a` if `condition` is 1, else `b`. This assumes that `condition` is already - /// checked to be a boolean. - #[inline] - fn if_else( - &mut self, - condition: impl Into + Clone, - a: impl Into + Clone, - b: impl Into + Clone, - ) -> Self::Expr { - condition.clone().into() * a.into() + (Self::Expr::one() - condition.into()) * b.into() - } - - /// Index an array of expressions using an index bitmap. This function assumes that the EIndex - /// type is a boolean and that index_bitmap's entries sum to 1. - fn index_array( - &mut self, - array: &[impl Into + Clone], - index_bitmap: &[impl Into + Clone], - ) -> Self::Expr { - let mut result = Self::Expr::zero(); - - for (value, i) in array.iter().zip_eq(index_bitmap) { - result += value.clone().into() * i.clone().into(); - } - - result - } -} - -/// A trait which contains methods for byte interactions in an AIR. -pub trait ByteAirBuilder: BaseAirBuilder { - /// Sends a byte operation to be processed. - #[allow(clippy::too_many_arguments)] - fn send_byte( - &mut self, - opcode: impl Into, - a: impl Into, - b: impl Into, - c: impl Into, - shard: impl Into, - channel: impl Into, - multiplicity: impl Into, - ) { - self.send_byte_pair( - opcode, - a, - Self::Expr::zero(), - b, - c, - shard, - channel, - multiplicity, - ) - } - - /// Sends a byte operation with two outputs to be processed. - #[allow(clippy::too_many_arguments)] - fn send_byte_pair( - &mut self, - opcode: impl Into, - a1: impl Into, - a2: impl Into, - b: impl Into, - c: impl Into, - shard: impl Into, - channel: impl Into, - multiplicity: impl Into, - ) { - self.send(AirInteraction::new( - vec![ - opcode.into(), - a1.into(), - a2.into(), - b.into(), - c.into(), - shard.into(), - channel.into(), - ], - multiplicity.into(), - InteractionKind::Byte, - )); - } - - /// Receives a byte operation to be processed. - #[allow(clippy::too_many_arguments)] - fn receive_byte( - &mut self, - opcode: impl Into, - a: impl Into, - b: impl Into, - c: impl Into, - shard: impl Into, - channel: impl Into, - multiplicity: impl Into, - ) { - self.receive_byte_pair( - opcode, - a, - Self::Expr::zero(), - b, - c, - shard, - channel, - multiplicity, - ) - } - - /// Receives a byte operation with two outputs to be processed. - #[allow(clippy::too_many_arguments)] - fn receive_byte_pair( - &mut self, - opcode: impl Into, - a1: impl Into, - a2: impl Into, - b: impl Into, - c: impl Into, - shard: impl Into, - channel: impl Into, - multiplicity: impl Into, - ) { - self.receive(AirInteraction::new( - vec![ - opcode.into(), - a1.into(), - a2.into(), - b.into(), - c.into(), - shard.into(), - channel.into(), - ], - multiplicity.into(), - InteractionKind::Byte, - )); - } -} - -/// A trait which contains methods related to words in an AIR. -pub trait WordAirBuilder: ByteAirBuilder { - /// Asserts that the two words are equal. - fn assert_word_eq( - &mut self, - left: Word>, - right: Word>, - ) { - for (left, right) in left.0.into_iter().zip(right.0) { - self.assert_eq(left, right); - } - } - - /// Asserts that the word is zero. - fn assert_word_zero(&mut self, word: Word>) { - for limb in word.0 { - self.assert_zero(limb); - } - } - - /// Index an array of words using an index bitmap. - fn index_word_array( - &mut self, - array: &[Word + Clone>], - index_bitmap: &[impl Into + Clone], - ) -> Word { - let mut result = Word::default(); - for i in 0..WORD_SIZE { - result[i] = self.index_array( - array - .iter() - .map(|word| word[i].clone()) - .collect_vec() - .as_slice(), - index_bitmap, - ); - } - result - } - - /// Same as `if_else` above, but arguments are `Word` instead of individual expressions. - fn select_word( - &mut self, - condition: impl Into + Clone, - a: Word + Clone>, - b: Word + Clone>, - ) -> Word { - Word(array::from_fn(|i| { - self.if_else(condition.clone(), a[i].clone(), b[i].clone()) - })) - } - - /// Check that each limb of the given slice is a u8. - fn slice_range_check_u8( - &mut self, - input: &[impl Into + Clone], - shard: impl Into + Clone, - channel: impl Into + Clone, - mult: impl Into + Clone, - ) { - let mut index = 0; - while index + 1 < input.len() { - self.send_byte( - Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), - Self::Expr::zero(), - input[index].clone(), - input[index + 1].clone(), - shard.clone(), - channel.clone(), - mult.clone(), - ); - index += 2; - } - if index < input.len() { - self.send_byte( - Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), - Self::Expr::zero(), - input[index].clone(), - Self::Expr::zero(), - shard.clone(), - channel.clone(), - mult.clone(), - ); - } - } - - /// Check that each limb of the given slice is a u16. - fn slice_range_check_u16( - &mut self, - input: &[impl Into + Copy], - shard: impl Into + Clone, - channel: impl Into + Clone, - mult: impl Into + Clone, - ) { - input.iter().for_each(|limb| { - self.send_byte( - Self::Expr::from_canonical_u8(ByteOpcode::U16Range as u8), - *limb, - Self::Expr::zero(), - Self::Expr::zero(), - shard.clone(), - channel.clone(), - mult.clone(), - ); - }); - } -} - -/// A trait which contains methods related to ALU interactions in an AIR. -pub trait AluAirBuilder: BaseAirBuilder { - /// Sends an ALU operation to be processed. - #[allow(clippy::too_many_arguments)] - fn send_alu( - &mut self, - opcode: impl Into, - a: Word>, - b: Word>, - c: Word>, - shard: impl Into, - channel: impl Into, - nonce: impl Into, - multiplicity: impl Into, - ) { - let values = once(opcode.into()) - .chain(a.0.into_iter().map(Into::into)) - .chain(b.0.into_iter().map(Into::into)) - .chain(c.0.into_iter().map(Into::into)) - .chain(once(shard.into())) - .chain(once(channel.into())) - .chain(once(nonce.into())) - .collect(); - - self.send(AirInteraction::new( - values, - multiplicity.into(), - InteractionKind::Alu, - )); - } - - /// Receives an ALU operation to be processed. - #[allow(clippy::too_many_arguments)] - fn receive_alu( - &mut self, - opcode: impl Into, - a: Word>, - b: Word>, - c: Word>, - shard: impl Into, - channel: impl Into, - nonce: impl Into, - multiplicity: impl Into, - ) { - let values = once(opcode.into()) - .chain(a.0.into_iter().map(Into::into)) - .chain(b.0.into_iter().map(Into::into)) - .chain(c.0.into_iter().map(Into::into)) - .chain(once(shard.into())) - .chain(once(channel.into())) - .chain(once(nonce.into())) - .collect(); - - self.receive(AirInteraction::new( - values, - multiplicity.into(), - InteractionKind::Alu, - )); - } - - /// Sends an syscall operation to be processed (with "ECALL" opcode). - #[allow(clippy::too_many_arguments)] - fn send_syscall( - &mut self, - shard: impl Into + Clone, - channel: impl Into + Clone, - clk: impl Into + Clone, - nonce: impl Into + Clone, - syscall_id: impl Into + Clone, - arg1: impl Into + Clone, - arg2: impl Into + Clone, - multiplicity: impl Into, - ) { - self.send(AirInteraction::new( - vec![ - shard.clone().into(), - channel.clone().into(), - clk.clone().into(), - nonce.clone().into(), - syscall_id.clone().into(), - arg1.clone().into(), - arg2.clone().into(), - ], - multiplicity.into(), - InteractionKind::Syscall, - )); - } - - /// Receives a syscall operation to be processed. - #[allow(clippy::too_many_arguments)] - fn receive_syscall( - &mut self, - shard: impl Into + Clone, - channel: impl Into + Clone, - clk: impl Into + Clone, - nonce: impl Into + Clone, - syscall_id: impl Into + Clone, - arg1: impl Into + Clone, - arg2: impl Into + Clone, - multiplicity: impl Into, - ) { - self.receive(AirInteraction::new( - vec![ - shard.clone().into(), - channel.clone().into(), - clk.clone().into(), - nonce.clone().into(), - syscall_id.clone().into(), - arg1.clone().into(), - arg2.clone().into(), - ], - multiplicity.into(), - InteractionKind::Syscall, - )); - } -} - -/// A trait which contains methods related to memory interactions in an AIR. -pub trait MemoryAirBuilder: BaseAirBuilder { - /// Constrain a memory read or write. - /// - /// This method verifies that a memory access timestamp (shard, clk) is greater than the - /// previous access's timestamp. It will also add to the memory argument. - fn eval_memory_access + Clone>( - &mut self, - shard: impl Into, - channel: impl Into, - clk: impl Into, - addr: impl Into, - memory_access: &impl MemoryCols, - do_check: impl Into, - ) { - let do_check: Self::Expr = do_check.into(); - let shard: Self::Expr = shard.into(); - let channel: Self::Expr = channel.into(); - let clk: Self::Expr = clk.into(); - let mem_access = memory_access.access(); - - self.assert_bool(do_check.clone()); - - // Verify that the current memory access time is greater than the previous's. - self.eval_memory_access_timestamp( - mem_access, - do_check.clone(), - shard.clone(), - channel, - clk.clone(), - ); - - // Add to the memory argument. - let addr = addr.into(); - let prev_shard = mem_access.prev_shard.clone().into(); - let prev_clk = mem_access.prev_clk.clone().into(); - let prev_values = once(prev_shard) - .chain(once(prev_clk)) - .chain(once(addr.clone())) - .chain(memory_access.prev_value().clone().map(Into::into)) - .collect(); - let current_values = once(shard) - .chain(once(clk)) - .chain(once(addr.clone())) - .chain(memory_access.value().clone().map(Into::into)) - .collect(); - - // The previous values get sent with multiplicity = 1, for "read". - self.send(AirInteraction::new( - prev_values, - do_check.clone(), - InteractionKind::Memory, - )); - - // The current values get "received", i.e. multiplicity = -1 - self.receive(AirInteraction::new( - current_values, - do_check.clone(), - InteractionKind::Memory, - )); - } - - /// Constraints a memory read or write to a slice of `MemoryAccessCols`. - fn eval_memory_access_slice + Copy>( - &mut self, - shard: impl Into + Copy, - channel: impl Into + Clone, - clk: impl Into + Clone, - initial_addr: impl Into + Clone, - memory_access_slice: &[impl MemoryCols], - verify_memory_access: impl Into + Copy, - ) { - for (i, access_slice) in memory_access_slice.iter().enumerate() { - self.eval_memory_access( - shard, - channel.clone(), - clk.clone(), - initial_addr.clone().into() + Self::Expr::from_canonical_usize(i * 4), - access_slice, - verify_memory_access, - ); - } - } - - /// Verifies the memory access timestamp. - /// - /// This method verifies that the current memory access happened after the previous one's. - /// Specifically it will ensure that if the current and previous access are in the same shard, - /// then the current's clk val is greater than the previous's. If they are not in the same - /// shard, then it will ensure that the current's shard val is greater than the previous's. - fn eval_memory_access_timestamp( - &mut self, - mem_access: &MemoryAccessCols + Clone>, - do_check: impl Into, - shard: impl Into + Clone, - channel: impl Into + Clone, - clk: impl Into, - ) { - let do_check: Self::Expr = do_check.into(); - let compare_clk: Self::Expr = mem_access.compare_clk.clone().into(); - let shard: Self::Expr = shard.clone().into(); - let prev_shard: Self::Expr = mem_access.prev_shard.clone().into(); - - // First verify that compare_clk's value is correct. - self.when(do_check.clone()).assert_bool(compare_clk.clone()); - self.when(do_check.clone()) - .when(compare_clk.clone()) - .assert_eq(shard.clone(), prev_shard); - - // Get the comparison timestamp values for the current and previous memory access. - let prev_comp_value = self.if_else( - mem_access.compare_clk.clone(), - mem_access.prev_clk.clone(), - mem_access.prev_shard.clone(), - ); - - let current_comp_val = self.if_else(compare_clk.clone(), clk.into(), shard.clone()); - - // Assert `current_comp_val > prev_comp_val`. We check this by asserting that - // `0 <= current_comp_val-prev_comp_val-1 < 2^24`. - // - // The equivalence of these statements comes from the fact that if - // `current_comp_val <= prev_comp_val`, then `current_comp_val-prev_comp_val-1 < 0` and will - // underflow in the prime field, resulting in a value that is `>= 2^24` as long as both - // `current_comp_val, prev_comp_val` are range-checked to be `<2^24` and as long as we're - // working in a field larger than `2 * 2^24` (which is true of the BabyBear and Mersenne31 - // prime). - let diff_minus_one = current_comp_val - prev_comp_value - Self::Expr::one(); - - // Verify that mem_access.ts_diff = mem_access.ts_diff_16bit_limb - // + mem_access.ts_diff_8bit_limb * 2^16. - self.eval_range_check_24bits( - diff_minus_one, - mem_access.diff_16bit_limb.clone(), - mem_access.diff_8bit_limb.clone(), - shard.clone(), - channel.clone(), - do_check, - ); - } - - /// Verifies the inputted value is within 24 bits. - /// - /// This method verifies that the inputted is less than 2^24 by doing a 16 bit and 8 bit range - /// check on it's limbs. It will also verify that the limbs are correct. This method is needed - /// since the memory access timestamp check (see [Self::verify_mem_access_ts]) needs to assume - /// the clk is within 24 bits. - fn eval_range_check_24bits( - &mut self, - value: impl Into, - limb_16: impl Into + Clone, - limb_8: impl Into + Clone, - shard: impl Into + Clone, - channel: impl Into + Clone, - do_check: impl Into + Clone, - ) { - // Verify that value = limb_16 + limb_8 * 2^16. - self.when(do_check.clone()).assert_eq( - value, - limb_16.clone().into() - + limb_8.clone().into() * Self::Expr::from_canonical_u32(1 << 16), - ); - - // Send the range checks for the limbs. - self.send_byte( - Self::Expr::from_canonical_u8(ByteOpcode::U16Range as u8), - limb_16, - Self::Expr::zero(), - Self::Expr::zero(), - shard.clone(), - channel.clone(), - do_check.clone(), - ); - - self.send_byte( - Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), - Self::Expr::zero(), - Self::Expr::zero(), - limb_8, - shard.clone(), - channel.clone(), - do_check, - ) - } -} - -/// A trait which contains methods related to program interactions in an AIR. -pub trait ProgramAirBuilder: BaseAirBuilder { - /// Sends an instruction. - fn send_program( - &mut self, - pc: impl Into, - instruction: InstructionCols + Copy>, - selectors: OpcodeSelectorCols + Copy>, - shard: impl Into + Copy, - multiplicity: impl Into, - ) { - let values = once(pc.into()) - .chain(once(instruction.opcode.into())) - .chain(instruction.into_iter().map(|x| x.into())) - .chain(selectors.into_iter().map(|x| x.into())) - .chain(once(shard.into())) - .collect(); - - self.send(AirInteraction::new( - values, - multiplicity.into(), - InteractionKind::Program, - )); - } - - /// Receives an instruction. - fn receive_program( - &mut self, - pc: impl Into, - instruction: InstructionCols + Copy>, - selectors: OpcodeSelectorCols + Copy>, - shard: impl Into + Copy, - multiplicity: impl Into, - ) { - let values: Vec<::Expr> = once(pc.into()) - .chain(once(instruction.opcode.into())) - .chain(instruction.into_iter().map(|x| x.into())) - .chain(selectors.into_iter().map(|x| x.into())) - .chain(once(shard.into())) - .collect(); - - self.receive(AirInteraction::new( - values, - multiplicity.into(), - InteractionKind::Program, - )); - } -} - -pub trait ExtensionAirBuilder: BaseAirBuilder { - /// Asserts that the two field extensions are equal. - fn assert_ext_eq>( - &mut self, - left: BinomialExtension, - right: BinomialExtension, - ) { - for (left, right) in left.0.into_iter().zip(right.0) { - self.assert_eq(left, right); - } - } - - /// Checks if an extension element is a base element. - fn assert_is_base_element + Clone>( - &mut self, - element: BinomialExtension, - ) { - let base_slice = element.as_base_slice(); - let degree = base_slice.len(); - base_slice[1..degree].iter().for_each(|coeff| { - self.assert_zero(coeff.clone().into()); - }); - } - - /// Performs an if else on extension elements. - fn if_else_ext( - &mut self, - condition: impl Into + Clone, - a: BinomialExtension + Clone>, - b: BinomialExtension + Clone>, - ) -> BinomialExtension { - BinomialExtension(array::from_fn(|i| { - self.if_else(condition.clone(), a.0[i].clone(), b.0[i].clone()) - })) - } -} - -pub trait MultiTableAirBuilder: PermutationAirBuilder { - type Sum: Into; - - fn cumulative_sum(&self) -> Self::Sum; -} - -/// A trait that contains the common helper methods for building `SP1 recursion` and SP1 machine AIRs. -pub trait MachineAirBuilder: - BaseAirBuilder + ExtensionAirBuilder + AirBuilderWithPublicValues -{ -} - -/// A trait which contains all helper methods for building SP1 machine AIRs. -pub trait SP1AirBuilder: - MachineAirBuilder - + ByteAirBuilder - + WordAirBuilder - + AluAirBuilder - + MemoryAirBuilder - + ProgramAirBuilder -{ -} - -impl<'a, AB: AirBuilder + MessageBuilder, M> MessageBuilder for FilteredAirBuilder<'a, AB> { - fn send(&mut self, message: M) { - self.inner.send(message); - } - - fn receive(&mut self, message: M) { - self.inner.receive(message); - } -} - -impl>> BaseAirBuilder for AB {} -impl ByteAirBuilder for AB {} -impl WordAirBuilder for AB {} -impl AluAirBuilder for AB {} -impl MemoryAirBuilder for AB {} -impl ProgramAirBuilder for AB {} -impl ExtensionAirBuilder for AB {} -impl MachineAirBuilder for AB {} -impl SP1AirBuilder for AB {} - -impl<'a, SC: StarkGenericConfig> EmptyMessageBuilder for ProverConstraintFolder<'a, SC> {} -impl<'a, SC: StarkGenericConfig> EmptyMessageBuilder for VerifierConstraintFolder<'a, SC> {} -impl EmptyMessageBuilder for SymbolicAirBuilder {} - -#[cfg(debug_assertions)] -#[cfg(not(doctest))] -impl<'a, F: Field> EmptyMessageBuilder for p3_uni_stark::DebugConstraintBuilder<'a, F> {} diff --git a/core/src/alu/mod.rs b/core/src/alu/mod.rs deleted file mode 100644 index 6ece69703d..0000000000 --- a/core/src/alu/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -pub mod add_sub; -pub mod bitwise; -pub mod divrem; -pub mod lt; -pub mod mul; -pub mod sll; -pub mod sr; - -pub use add_sub::*; -pub use bitwise::*; -pub use divrem::*; -pub use lt::*; -pub use mul::*; -use rand::Rng; -pub use sll::*; -pub use sr::*; - -use serde::{Deserialize, Serialize}; - -use crate::runtime::Opcode; - -/// A standard format for describing ALU operations that need to be proven. -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct AluEvent { - /// The lookup id of the event. - pub lookup_id: u128, - - /// The shard number, used for byte lookup table. - pub shard: u32, - - /// The channel number, used for byte lookup table. - pub channel: u8, - - /// The clock cycle that the operation occurs on. - pub clk: u32, - - /// The opcode of the operation. - pub opcode: Opcode, - - /// The result of the operation. - pub a: u32, - - /// The first input operand. - pub b: u32, - - // The second input operand. - pub c: u32, - - pub sub_lookups: [u128; 6], -} - -impl AluEvent { - /// Creates a new `AluEvent`. - pub fn new(shard: u32, channel: u8, clk: u32, opcode: Opcode, a: u32, b: u32, c: u32) -> Self { - Self { - lookup_id: 0, - shard, - channel, - clk, - opcode, - a, - b, - c, - sub_lookups: create_alu_lookups(), - } - } -} - -pub fn create_alu_lookup_id() -> u128 { - let mut rng = rand::thread_rng(); - rng.gen() -} - -pub fn create_alu_lookups() -> [u128; 6] { - let mut rng = rand::thread_rng(); - [ - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - ] -} diff --git a/core/src/bytes/opcode.rs b/core/src/bytes/opcode.rs deleted file mode 100644 index 8fae62ad6d..0000000000 --- a/core/src/bytes/opcode.rs +++ /dev/null @@ -1,72 +0,0 @@ -use p3_field::Field; -use serde::{Deserialize, Serialize}; - -use crate::{bytes::NUM_BYTE_OPS, runtime::Opcode}; - -/// A byte opcode which the chip can process. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub enum ByteOpcode { - /// Bitwise AND. - AND = 0, - - /// Bitwise OR. - OR = 1, - - /// Bitwise XOR. - XOR = 2, - - /// Shift Left. - SLL = 3, - - /// U8 Range check. - U8Range = 4, - - /// Shift right with carry. - ShrCarry = 5, - - /// Byte less than unsigned. - LTU = 6, - - /// The most significant bit of the given byte. - MSB = 7, - - /// U16 Range check. - U16Range = 8, -} - -impl ByteOpcode { - /// Get all the byte opcodes. - pub fn all() -> Vec { - let opcodes = vec![ - ByteOpcode::AND, - ByteOpcode::OR, - ByteOpcode::XOR, - ByteOpcode::SLL, - ByteOpcode::U8Range, - ByteOpcode::ShrCarry, - ByteOpcode::LTU, - ByteOpcode::MSB, - ByteOpcode::U16Range, - ]; - assert_eq!(opcodes.len(), NUM_BYTE_OPS); - opcodes - } - - /// Convert the opcode to a field element. - pub fn as_field(self) -> F { - F::from_canonical_u8(self as u8) - } -} - -impl From for ByteOpcode { - /// Convert an opcode to a byte opcode. - fn from(value: Opcode) -> Self { - match value { - Opcode::AND => Self::AND, - Opcode::OR => Self::OR, - Opcode::XOR => Self::XOR, - Opcode::SLL => Self::SLL, - _ => panic!("Invalid opcode for ByteChip: {:?}", value), - } - } -} diff --git a/core/src/disassembler/mod.rs b/core/src/disassembler/mod.rs deleted file mode 100644 index a6a89f7f9e..0000000000 --- a/core/src/disassembler/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -mod elf; -mod instruction; - -pub use elf::*; -pub use instruction::*; - -use std::{collections::BTreeMap, fs::File, io::Read}; - -use crate::runtime::{Instruction, Program}; - -impl Program { - /// Create a new program. - pub const fn new(instructions: Vec, pc_start: u32, pc_base: u32) -> Self { - Self { - instructions, - pc_start, - pc_base, - memory_image: BTreeMap::new(), - } - } - - /// Disassemble a RV32IM ELF to a program that be executed by the VM. - pub fn from(input: &[u8]) -> Self { - // Decode the bytes as an ELF. - let elf = Elf::decode(input); - - // Transpile the RV32IM instructions. - let instructions = transpile(&elf.instructions); - - // Return the program. - Program { - instructions, - pc_start: elf.pc_start, - pc_base: elf.pc_base, - memory_image: elf.memory_image, - } - } - - /// Disassemble a RV32IM ELF to a program that be executed by the VM from a file path. - pub fn from_elf(path: &str) -> Self { - let mut elf_code = Vec::new(); - File::open(path) - .expect("failed to open input file") - .read_to_end(&mut elf_code) - .expect("failed to read from input file"); - Program::from(&elf_code) - } -} diff --git a/core/src/memory/mod.rs b/core/src/memory/mod.rs deleted file mode 100644 index 90198d541e..0000000000 --- a/core/src/memory/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -mod columns; -mod global; -mod program; -mod trace; - -pub use columns::*; -pub use global::*; -pub use program::*; - -use serde::{Deserialize, Serialize}; - -use crate::runtime::MemoryRecord; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct MemoryInitializeFinalizeEvent { - pub addr: u32, - pub value: u32, - pub shard: u32, - pub timestamp: u32, - pub used: u32, -} - -impl MemoryInitializeFinalizeEvent { - pub const fn initialize(addr: u32, value: u32, used: bool) -> Self { - // All memory initialization happen at shard 0, timestamp 0. - Self { - addr, - value, - shard: 1, - timestamp: 1, - used: if used { 1 } else { 0 }, - } - } - - pub const fn finalize_from_record(addr: u32, record: &MemoryRecord) -> Self { - Self { - addr, - value: record.value, - shard: record.shard, - timestamp: record.timestamp, - used: 1, - } - } -} diff --git a/core/src/runtime/io.rs b/core/src/runtime/io.rs deleted file mode 100644 index cbc927e459..0000000000 --- a/core/src/runtime/io.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::io::Read; - -use crate::stark::{ShardProof, StarkVerifyingKey}; -use crate::utils::BabyBearPoseidon2; - -use serde::de::DeserializeOwned; -use serde::Serialize; - -use super::Runtime; - -impl<'a> Read for Runtime<'a> { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.read_public_values_slice(buf); - Ok(buf.len()) - } -} - -impl<'a> Runtime<'a> { - pub fn write_stdin(&mut self, input: &T) { - let mut buf = Vec::new(); - bincode::serialize_into(&mut buf, input).expect("serialization failed"); - self.state.input_stream.push(buf); - } - - pub fn write_stdin_slice(&mut self, input: &[u8]) { - self.state.input_stream.push(input.to_vec()); - } - - pub fn write_vecs(&mut self, inputs: &[Vec]) { - for input in inputs { - self.state.input_stream.push(input.clone()); - } - } - - pub fn write_proof( - &mut self, - proof: ShardProof, - vk: StarkVerifyingKey, - ) { - self.state.proof_stream.push((proof, vk)); - } - - pub fn read_public_values(&mut self) -> T { - let result = bincode::deserialize_from::<_, T>(self); - result.unwrap() - } - - pub fn read_public_values_slice(&mut self, buf: &mut [u8]) { - let len = buf.len(); - let start = self.state.public_values_stream_ptr; - let end = start + len; - assert!(end <= self.state.public_values_stream.len()); - buf.copy_from_slice(&self.state.public_values_stream[start..end]); - self.state.public_values_stream_ptr = end; - } -} - -#[cfg(test)] -pub mod tests { - use super::*; - use crate::runtime::Program; - use crate::stark::CpuProver; - use crate::utils::tests::IO_ELF; - use crate::utils::{self, prove_simple, BabyBearBlake3, SP1CoreOpts}; - use serde::Deserialize; - - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct MyPointUnaligned { - pub x: usize, - pub y: usize, - pub b: bool, - } - - fn points() -> (MyPointUnaligned, MyPointUnaligned) { - ( - MyPointUnaligned { - x: 3, - y: 5, - b: true, - }, - MyPointUnaligned { - x: 8, - y: 19, - b: true, - }, - ) - } - - #[test] - fn test_io_run() { - utils::setup_logger(); - let program = Program::from(IO_ELF); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); - let points = points(); - runtime.write_stdin(&points.0); - runtime.write_stdin(&points.1); - runtime.run().unwrap(); - let added_point = runtime.read_public_values::(); - assert_eq!( - added_point, - MyPointUnaligned { - x: 11, - y: 24, - b: true - } - ); - } - - #[test] - fn test_io_prove() { - utils::setup_logger(); - let program = Program::from(IO_ELF); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); - let points = points(); - runtime.write_stdin(&points.0); - runtime.write_stdin(&points.1); - runtime.run().unwrap(); - let config = BabyBearBlake3::new(); - prove_simple::<_, CpuProver<_, _>>(config, runtime).unwrap(); - } -} diff --git a/core/src/runtime/memory.rs b/core/src/runtime/memory.rs deleted file mode 100644 index 4e66245187..0000000000 --- a/core/src/runtime/memory.rs +++ /dev/null @@ -1,116 +0,0 @@ -use serde::{Deserialize, Serialize}; - -/// An record of a write to a memory address. -#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] -pub struct MemoryRecord { - /// The value at the memory address. - pub value: u32, - - /// The shard in which the memory address was last written to. - pub shard: u32, - - /// The timestamp at which the memory address was last written to. - pub timestamp: u32, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum MemoryAccessPosition { - Memory = 0, - // Note that these AccessPositions mean that when when read/writing registers, they must be - // read/written in the following order: C, B, A. - C = 1, - B = 2, - A = 3, -} - -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub enum MemoryRecordEnum { - Read(MemoryReadRecord), - Write(MemoryWriteRecord), -} - -#[allow(clippy::manual_non_exhaustive)] -#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] -pub struct MemoryReadRecord { - pub value: u32, - pub shard: u32, - pub timestamp: u32, - pub prev_shard: u32, - pub prev_timestamp: u32, - _private: (), -} - -#[allow(clippy::manual_non_exhaustive)] -#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] -pub struct MemoryWriteRecord { - pub value: u32, - pub shard: u32, - pub timestamp: u32, - pub prev_value: u32, - pub prev_shard: u32, - pub prev_timestamp: u32, - _private: (), -} - -impl MemoryRecordEnum { - pub const fn value(&self) -> u32 { - match self { - MemoryRecordEnum::Read(record) => record.value, - MemoryRecordEnum::Write(record) => record.value, - } - } -} - -impl From for MemoryRecordEnum { - fn from(read_record: MemoryReadRecord) -> Self { - MemoryRecordEnum::Read(read_record) - } -} - -impl From for MemoryRecordEnum { - fn from(write_record: MemoryWriteRecord) -> Self { - MemoryRecordEnum::Write(write_record) - } -} - -impl MemoryReadRecord { - pub const fn new( - value: u32, - shard: u32, - timestamp: u32, - prev_shard: u32, - prev_timestamp: u32, - ) -> Self { - assert!(shard > prev_shard || ((shard == prev_shard) && (timestamp > prev_timestamp))); - Self { - value, - shard, - timestamp, - prev_shard, - prev_timestamp, - _private: (), - } - } -} - -impl MemoryWriteRecord { - pub const fn new( - value: u32, - shard: u32, - timestamp: u32, - prev_value: u32, - prev_shard: u32, - prev_timestamp: u32, - ) -> Self { - assert!(shard > prev_shard || ((shard == prev_shard) && (timestamp > prev_timestamp)),); - Self { - value, - shard, - timestamp, - prev_value, - prev_shard, - prev_timestamp, - _private: (), - } - } -} diff --git a/core/src/runtime/opcode.rs b/core/src/runtime/opcode.rs deleted file mode 100644 index 3eaf8caa88..0000000000 --- a/core/src/runtime/opcode.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::fmt::Display; - -use p3_field::Field; -use serde::{Deserialize, Serialize}; - -/// An opcode specifies which operation to execute. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[allow(non_camel_case_types)] -pub enum Opcode { - // Arithmetic instructions. - ADD = 0, - SUB = 1, - XOR = 2, - OR = 3, - AND = 4, - SLL = 5, - SRL = 6, - SRA = 7, - SLT = 8, - SLTU = 9, - - // Load instructions. - LB = 10, - LH = 11, - LW = 12, - LBU = 13, - LHU = 14, - - // Store instructions. - SB = 15, - SH = 16, - SW = 17, - - // Branch instructions. - BEQ = 18, - BNE = 19, - BLT = 20, - BGE = 21, - BLTU = 22, - BGEU = 23, - - // Jump instructions. - JAL = 24, - JALR = 25, - AUIPC = 27, - - // System instructions. - ECALL = 28, - EBREAK = 29, - - // Multiplication instructions. - MUL = 30, - MULH = 31, - MULHU = 32, - MULHSU = 33, - DIV = 34, - DIVU = 35, - REM = 36, - REMU = 37, - - // Miscellaneaous instructions. - UNIMP = 39, -} - -impl Display for Opcode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.mnemonic()) - } -} - -impl Opcode { - pub const fn mnemonic(&self) -> &str { - match self { - Opcode::ADD => "add", - Opcode::SUB => "sub", - Opcode::XOR => "xor", - Opcode::OR => "or", - Opcode::AND => "and", - Opcode::SLL => "sll", - Opcode::SRL => "srl", - Opcode::SRA => "sra", - Opcode::SLT => "slt", - Opcode::SLTU => "sltu", - Opcode::LB => "lb", - Opcode::LH => "lh", - Opcode::LW => "lw", - Opcode::LBU => "lbu", - Opcode::LHU => "lhu", - Opcode::SB => "sb", - Opcode::SH => "sh", - Opcode::SW => "sw", - Opcode::BEQ => "beq", - Opcode::BNE => "bne", - Opcode::BLT => "blt", - Opcode::BGE => "bge", - Opcode::BLTU => "bltu", - Opcode::BGEU => "bgeu", - Opcode::JAL => "jal", - Opcode::JALR => "jalr", - Opcode::AUIPC => "auipc", - Opcode::ECALL => "ecall", - Opcode::EBREAK => "ebreak", - Opcode::MUL => "mul", - Opcode::MULH => "mulh", - Opcode::MULHU => "mulhu", - Opcode::MULHSU => "mulhsu", - Opcode::DIV => "div", - Opcode::DIVU => "divu", - Opcode::REM => "rem", - Opcode::REMU => "remu", - Opcode::UNIMP => "unimp", - } - } -} - -impl Opcode { - pub fn as_field(self) -> F { - F::from_canonical_u32(self as u32) - } -} diff --git a/core/src/runtime/program.rs b/core/src/runtime/program.rs deleted file mode 100644 index 065394a8ca..0000000000 --- a/core/src/runtime/program.rs +++ /dev/null @@ -1,20 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; - -use super::Instruction; - -/// A program that can be executed by the VM. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Program { - /// The instructions of the program. - pub instructions: Vec, - - /// The start address of the program. - pub pc_start: u32, - - /// The base address of the program. - pub pc_base: u32, - - /// The initial memory image, useful for global constants. - pub memory_image: BTreeMap, -} diff --git a/core/src/runtime/report.rs b/core/src/runtime/report.rs deleted file mode 100644 index 62e85f108b..0000000000 --- a/core/src/runtime/report.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::collections::hash_map::Entry; -use std::collections::HashMap; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::hash::Hash; -use std::ops::{Add, AddAssign}; - -use super::*; - -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct ExecutionReport { - pub opcode_counts: HashMap, - pub syscall_counts: HashMap, -} - -impl ExecutionReport { - /// Compute the total number of instructions run during the execution. - pub fn total_instruction_count(&self) -> u64 { - self.opcode_counts.values().sum() - } - - /// Compute the total number of syscalls made during the execution. - pub fn total_syscall_count(&self) -> u64 { - self.syscall_counts.values().sum() - } - - /// Returns sorted and formatted rows of a table of counts (e.g. `opcode_counts`). - /// - /// The table is sorted first by count (descending) and then by label (ascending). - /// The first column consists of the counts, is right-justified, and is padded precisely - /// enough to fit all the numbers. The second column consists of the labels (e.g. `OpCode`s). - /// The columns are separated by a single space character. - pub fn sorted_table_lines(table: &HashMap) -> Vec - where - K: Ord + Display, - V: Ord + Display, - { - // This function could be optimized here and there, - // for example by pre-allocating all `Vec`s, or by using less memory. - let mut lines = Vec::with_capacity(table.len()); - let mut entries = table.iter().collect::>(); - // Sort table by count (descending), then the name order (ascending). - entries.sort_unstable_by(|a, b| a.1.cmp(b.1).reverse().then_with(|| a.0.cmp(b.0))); - // Convert counts to `String`s to prepare them for printing and to measure their width. - let table_with_string_counts = entries - .into_iter() - .map(|(label, ct)| (label.to_string().to_lowercase(), ct.to_string())) - .collect::>(); - // Calculate width for padding the counts. - let width = table_with_string_counts - .first() - .map(|(_, b)| b.len()) - .unwrap_or_default(); - for (label, count) in table_with_string_counts { - lines.push(format!("{count:>width$} {label}")); - } - lines - } -} - -/// Combines two `HashMap`s together. If a key is in both maps, the values are added together. -fn hashmap_add_assign(lhs: &mut HashMap, rhs: HashMap) -where - K: Eq + Hash, - V: AddAssign, -{ - for (k, v) in rhs.into_iter() { - // Can't use `.and_modify(...).or_insert(...)` because we want to use `v` in both places. - match lhs.entry(k) { - Entry::Occupied(e) => *e.into_mut() += v, - Entry::Vacant(e) => drop(e.insert(v)), - } - } -} - -impl AddAssign for ExecutionReport { - fn add_assign(&mut self, rhs: Self) { - hashmap_add_assign(&mut self.opcode_counts, rhs.opcode_counts); - hashmap_add_assign(&mut self.syscall_counts, rhs.syscall_counts); - } -} - -impl Add for ExecutionReport { - type Output = Self; - - fn add(mut self, rhs: Self) -> Self::Output { - self += rhs; - self - } -} - -impl Display for ExecutionReport { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - writeln!( - f, - "opcode counts ({} total instructions):", - self.total_instruction_count() - )?; - for line in Self::sorted_table_lines(&self.opcode_counts) { - writeln!(f, " {line}")?; - } - - writeln!( - f, - "syscall counts ({} total syscall instructions):", - self.total_syscall_count() - )?; - for line in Self::sorted_table_lines(&self.syscall_counts) { - writeln!(f, " {line}")?; - } - - Ok(()) - } -} diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs deleted file mode 100644 index 433fcdcc10..0000000000 --- a/core/src/stark/air.rs +++ /dev/null @@ -1,193 +0,0 @@ -use super::StarkMachine; -pub use crate::air::SP1AirBuilder; -use crate::air::{MachineAir, SP1_PROOF_NUM_PV_ELTS}; -use crate::memory::{MemoryChipType, MemoryProgramChip}; -use crate::stark::Chip; -use crate::StarkGenericConfig; -use p3_field::PrimeField32; -pub use riscv_chips::*; -use tracing::instrument; - -/// A module for importing all the different RISC-V chips. -pub(crate) mod riscv_chips { - pub use crate::alu::AddSubChip; - pub use crate::alu::BitwiseChip; - pub use crate::alu::DivRemChip; - pub use crate::alu::LtChip; - pub use crate::alu::MulChip; - pub use crate::alu::ShiftLeft; - pub use crate::alu::ShiftRightChip; - pub use crate::bytes::ByteChip; - pub use crate::cpu::CpuChip; - pub use crate::memory::MemoryChip; - pub use crate::program::ProgramChip; - pub use crate::syscall::precompiles::edwards::EdAddAssignChip; - pub use crate::syscall::precompiles::edwards::EdDecompressChip; - pub use crate::syscall::precompiles::keccak256::KeccakPermuteChip; - pub use crate::syscall::precompiles::sha256::ShaCompressChip; - pub use crate::syscall::precompiles::sha256::ShaExtendChip; - pub use crate::syscall::precompiles::uint256::Uint256MulChip; - pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; - pub use crate::syscall::precompiles::weierstrass::WeierstrassDecompressChip; - pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; - pub use crate::utils::ec::edwards::ed25519::Ed25519Parameters; - pub use crate::utils::ec::edwards::EdwardsCurve; - pub use crate::utils::ec::weierstrass::bls12_381::Bls12381Parameters; - pub use crate::utils::ec::weierstrass::bn254::Bn254Parameters; - pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; - pub use crate::utils::ec::weierstrass::SwCurve; -} - -/// An AIR for encoding RISC-V execution. -/// -/// This enum contains all the different AIRs that are used in the Sp1 RISC-V IOP. Each variant is -/// a different AIR that is used to encode a different part of the RISC-V execution, and the -/// different AIR variants have a joint lookup argument. -#[derive(MachineAir)] -pub enum RiscvAir { - /// An AIR that containts a preprocessed program table and a lookup for the instructions. - Program(ProgramChip), - /// An AIR for the RISC-V CPU. Each row represents a cpu cycle. - Cpu(CpuChip), - /// An AIR for the RISC-V Add and SUB instruction. - Add(AddSubChip), - /// An AIR for RISC-V Bitwise instructions. - Bitwise(BitwiseChip), - /// An AIR for RISC-V Mul instruction. - Mul(MulChip), - /// An AIR for RISC-V Div and Rem instructions. - DivRem(DivRemChip), - /// An AIR for RISC-V Lt instruction. - Lt(LtChip), - /// An AIR for RISC-V SLL instruction. - ShiftLeft(ShiftLeft), - /// An AIR for RISC-V SRL and SRA instruction. - ShiftRight(ShiftRightChip), - /// A lookup table for byte operations. - ByteLookup(ByteChip), - /// A table for initializing the memory state. - MemoryInit(MemoryChip), - /// A table for finalizing the memory state. - MemoryFinal(MemoryChip), - /// A table for initializing the program memory. - ProgramMemory(MemoryProgramChip), - /// A precompile for sha256 extend. - Sha256Extend(ShaExtendChip), - /// A precompile for sha256 compress. - Sha256Compress(ShaCompressChip), - /// A precompile for addition on the Elliptic curve ed25519. - Ed25519Add(EdAddAssignChip>), - /// A precompile for decompressing a point on the Edwards curve ed25519. - Ed25519Decompress(EdDecompressChip), - /// A precompile for decompressing a point on the K256 curve. - K256Decompress(WeierstrassDecompressChip>), - /// A precompile for addition on the Elliptic curve secp256k1. - Secp256k1Add(WeierstrassAddAssignChip>), - /// A precompile for doubling a point on the Elliptic curve secp256k1. - Secp256k1Double(WeierstrassDoubleAssignChip>), - /// A precompile for the Keccak permutation. - KeccakP(KeccakPermuteChip), - /// A precompile for addition on the Elliptic curve bn254. - Bn254Add(WeierstrassAddAssignChip>), - /// A precompile for doubling a point on the Elliptic curve bn254. - Bn254Double(WeierstrassDoubleAssignChip>), - /// A precompile for addition on the Elliptic curve bls12_381. - Bls12381Add(WeierstrassAddAssignChip>), - /// A precompile for doubling a point on the Elliptic curve bls12_381. - Bls12381Double(WeierstrassDoubleAssignChip>), - /// A precompile for uint256 mul. - Uint256Mul(Uint256MulChip), - /// A precompile for decompressing a point on the BLS12-381 curve. - Bls12381Decompress(WeierstrassDecompressChip>), -} - -impl RiscvAir { - #[instrument("construct RiscvAir machine", level = "debug", skip_all)] - pub fn machine>(config: SC) -> StarkMachine { - let chips = Self::get_all() - .into_iter() - .map(Chip::new) - .collect::>(); - StarkMachine::new(config, chips, SP1_PROOF_NUM_PV_ELTS) - } - - /// Get all the different RISC-V AIRs. - pub fn get_all() -> Vec { - // The order of the chips is important, as it is used to determine the order of trace - // generation. In the future, we will detect that order automatically. - let mut chips = vec![]; - let cpu = CpuChip::default(); - chips.push(RiscvAir::Cpu(cpu)); - let program = ProgramChip::default(); - chips.push(RiscvAir::Program(program)); - let sha_extend = ShaExtendChip::default(); - chips.push(RiscvAir::Sha256Extend(sha_extend)); - let sha_compress = ShaCompressChip::default(); - chips.push(RiscvAir::Sha256Compress(sha_compress)); - let ed_add_assign = EdAddAssignChip::>::new(); - chips.push(RiscvAir::Ed25519Add(ed_add_assign)); - let ed_decompress = EdDecompressChip::::default(); - chips.push(RiscvAir::Ed25519Decompress(ed_decompress)); - let k256_decompress = - WeierstrassDecompressChip::>::with_lsb_rule(); - chips.push(RiscvAir::K256Decompress(k256_decompress)); - let secp256k1_add_assign = WeierstrassAddAssignChip::>::new(); - chips.push(RiscvAir::Secp256k1Add(secp256k1_add_assign)); - let secp256k1_double_assign = - WeierstrassDoubleAssignChip::>::new(); - chips.push(RiscvAir::Secp256k1Double(secp256k1_double_assign)); - let keccak_permute = KeccakPermuteChip::new(); - chips.push(RiscvAir::KeccakP(keccak_permute)); - let bn254_add_assign = WeierstrassAddAssignChip::>::new(); - chips.push(RiscvAir::Bn254Add(bn254_add_assign)); - let bn254_double_assign = WeierstrassDoubleAssignChip::>::new(); - chips.push(RiscvAir::Bn254Double(bn254_double_assign)); - let bls12381_add = WeierstrassAddAssignChip::>::new(); - chips.push(RiscvAir::Bls12381Add(bls12381_add)); - let bls12381_double = WeierstrassDoubleAssignChip::>::new(); - chips.push(RiscvAir::Bls12381Double(bls12381_double)); - let uint256_mul = Uint256MulChip::default(); - chips.push(RiscvAir::Uint256Mul(uint256_mul)); - let bls12381_decompress = - WeierstrassDecompressChip::>::with_lexicographic_rule(); - chips.push(RiscvAir::Bls12381Decompress(bls12381_decompress)); - let div_rem = DivRemChip::default(); - chips.push(RiscvAir::DivRem(div_rem)); - let add = AddSubChip::default(); - chips.push(RiscvAir::Add(add)); - let bitwise = BitwiseChip::default(); - chips.push(RiscvAir::Bitwise(bitwise)); - let mul = MulChip::default(); - chips.push(RiscvAir::Mul(mul)); - let shift_right = ShiftRightChip::default(); - chips.push(RiscvAir::ShiftRight(shift_right)); - let shift_left = ShiftLeft::default(); - chips.push(RiscvAir::ShiftLeft(shift_left)); - let lt = LtChip::default(); - chips.push(RiscvAir::Lt(lt)); - let memory_init = MemoryChip::new(MemoryChipType::Initialize); - chips.push(RiscvAir::MemoryInit(memory_init)); - let memory_finalize = MemoryChip::new(MemoryChipType::Finalize); - chips.push(RiscvAir::MemoryFinal(memory_finalize)); - let program_memory_init = MemoryProgramChip::new(); - chips.push(RiscvAir::ProgramMemory(program_memory_init)); - let byte = ByteChip::default(); - chips.push(RiscvAir::ByteLookup(byte)); - - chips - } -} - -impl PartialEq for RiscvAir { - fn eq(&self, other: &Self) -> bool { - self.name() == other.name() - } -} - -impl Eq for RiscvAir {} - -impl core::hash::Hash for RiscvAir { - fn hash(&self, state: &mut H) { - self.name().hash(state); - } -} diff --git a/core/src/stark/mod.rs b/core/src/stark/mod.rs deleted file mode 100644 index c9855b6b66..0000000000 --- a/core/src/stark/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -mod air; -mod chip; -mod config; -mod debug; -mod folder; -mod machine; -mod permutation; -mod prover; -mod quotient; -mod record; -mod types; -mod util; -mod verifier; - -pub use air::*; -pub use chip::*; -pub use config::*; -pub use debug::*; -pub use folder::*; -pub use machine::*; -pub use permutation::*; -pub use prover::*; -pub use quotient::*; -pub use record::*; -pub use types::*; -pub use verifier::*; - -#[allow(unused_imports)] -pub(crate) use air::riscv_chips; - -#[cfg(test)] -pub use machine::tests; diff --git a/core/src/syscall/commit.rs b/core/src/syscall/commit.rs deleted file mode 100644 index 7c8fcabc15..0000000000 --- a/core/src/syscall/commit.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::runtime::{Syscall, SyscallContext}; - -/// A syscall that commits a word of the public values digest. -pub struct SyscallCommit; - -impl SyscallCommit { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallCommit { - fn execute( - &self, - ctx: &mut SyscallContext, - word_idx: u32, - public_values_digest_word: u32, - ) -> Option { - let rt = &mut ctx.rt; - - rt.record.public_values.committed_value_digest[word_idx as usize] = - public_values_digest_word; - - None - } -} - -/// Commit to one word within the digest of deferred proofs. Takes in an index and a word. -pub struct SyscallCommitDeferred; - -impl SyscallCommitDeferred { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallCommitDeferred { - fn execute(&self, ctx: &mut SyscallContext, word_idx: u32, word: u32) -> Option { - let rt = &mut ctx.rt; - - rt.record.public_values.deferred_proofs_digest[word_idx as usize] = word; - - None - } -} diff --git a/core/src/syscall/mod.rs b/core/src/syscall/mod.rs deleted file mode 100644 index a2f7950619..0000000000 --- a/core/src/syscall/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod commit; -mod halt; -mod hint; -pub mod precompiles; -mod unconstrained; -mod verify; -mod write; - -pub use commit::*; -pub use halt::*; -pub use hint::*; -pub use unconstrained::*; -pub use verify::*; -pub use write::*; diff --git a/core/src/syscall/precompiles/edwards/mod.rs b/core/src/syscall/precompiles/edwards/mod.rs deleted file mode 100644 index ff09b4214d..0000000000 --- a/core/src/syscall/precompiles/edwards/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod ed_add; -mod ed_decompress; - -pub use ed_add::*; -pub use ed_decompress::*; - -use crate::operations::field::params::{NumLimbs, NumWords}; -use crate::utils::ec::edwards::ed25519::Ed25519BaseField; -use typenum::Unsigned; - -pub(crate) type Limbs = ::Limbs; -pub(crate) const NUM_LIMBS: usize = Limbs::USIZE; - -pub(crate) type WordsFieldElement = ::WordsFieldElement; -pub(crate) const WORDS_FIELD_ELEMENT: usize = WordsFieldElement::USIZE; - -#[allow(unused)] -pub(crate) type WordsCurvePoint = ::WordsCurvePoint; -pub(crate) const WORDS_CURVE_POINT: usize = WordsCurvePoint::USIZE; diff --git a/core/src/syscall/precompiles/keccak256/execute.rs b/core/src/syscall/precompiles/keccak256/execute.rs deleted file mode 100644 index eecc747bed..0000000000 --- a/core/src/syscall/precompiles/keccak256/execute.rs +++ /dev/null @@ -1,119 +0,0 @@ -use p3_keccak_air::{NUM_ROUNDS, RC}; - -use super::{KeccakPermuteChip, STATE_NUM_WORDS, STATE_SIZE}; -use crate::{ - runtime::Syscall, - syscall::precompiles::{keccak256::KeccakPermuteEvent, SyscallContext}, -}; - -const RHO: [u32; 24] = [ - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, -]; - -const PI: [usize; 24] = [ - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, -]; - -impl Syscall for KeccakPermuteChip { - fn num_extra_cycles(&self) -> u32 { - 1 - } - - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let start_clk = rt.clk; - let state_ptr = arg1; - if arg2 != 0 { - panic!("Expected arg2 to be 0, got {}", arg2); - } - - let mut state_read_records = Vec::new(); - let mut state_write_records = Vec::new(); - - let mut state = Vec::new(); - - let (state_records, state_values) = rt.mr_slice(state_ptr, STATE_NUM_WORDS); - state_read_records.extend_from_slice(&state_records); - - for values in state_values.chunks_exact(2) { - let least_sig = values[0]; - let most_sig = values[1]; - state.push(least_sig as u64 + ((most_sig as u64) << 32)); - } - - let saved_state = state.clone(); - - for i in 0..NUM_ROUNDS { - let mut array: [u64; 5 * 5] = [0; 5 * 5]; - - // Theta - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - array[x] ^= state[x + y]; - } - } - - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - state[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1); - } - } - - // Rho and pi - let mut last = state[1]; - for x in 0..24 { - array[0] = state[PI[x]]; - state[PI[x]] = last.rotate_left(RHO[x]); - last = array[0]; - } - - // Chi - for y_step in 0..5 { - let y = y_step * 5; - - array[..5].copy_from_slice(&state[y..(5 + y)]); - - for x in 0..5 { - state[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5])); - } - } - - // Iota - state[0] ^= RC[i]; - } - - // Increment the clk by 1 before writing because we read from memory at start_clk. - rt.clk += 1; - let mut values_to_write = Vec::new(); - for i in 0..STATE_SIZE { - let most_sig = ((state[i] >> 32) & 0xFFFFFFFF) as u32; - let least_sig = (state[i] & 0xFFFFFFFF) as u32; - values_to_write.push(least_sig); - values_to_write.push(most_sig); - } - - let write_records = rt.mw_slice(state_ptr, values_to_write.as_slice()); - state_write_records.extend_from_slice(&write_records); - - // Push the Keccak permute event. - let shard = rt.current_shard(); - let channel = rt.current_channel(); - let lookup_id = rt.syscall_lookup_id; - rt.record_mut() - .keccak_permute_events - .push(KeccakPermuteEvent { - lookup_id, - shard, - channel, - clk: start_clk, - pre_state: saved_state.as_slice().try_into().unwrap(), - post_state: state.as_slice().try_into().unwrap(), - state_read_records, - state_write_records, - state_addr: state_ptr, - }); - - None - } -} diff --git a/core/src/syscall/write.rs b/core/src/syscall/write.rs deleted file mode 100644 index 8e9d389cbd..0000000000 --- a/core/src/syscall/write.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::{ - runtime::{Register, Syscall, SyscallContext}, - utils::num_to_comma_separated, -}; - -pub struct SyscallWrite; - -impl SyscallWrite { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallWrite { - fn execute(&self, ctx: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let a2 = Register::X12; - let rt = &mut ctx.rt; - let fd = arg1; - let write_buf = arg2; - let nbytes = rt.register(a2); - // Read nbytes from memory starting at write_buf. - let bytes = (0..nbytes) - .map(|i| rt.byte(write_buf + i)) - .collect::>(); - let slice = bytes.as_slice(); - if fd == 1 { - let s = core::str::from_utf8(slice).unwrap(); - if s.contains("cycle-tracker-start:") { - let fn_name = s - .split("cycle-tracker-start:") - .last() - .unwrap() - .trim_end() - .trim_start(); - let depth = rt.cycle_tracker.len() as u32; - rt.cycle_tracker - .insert(fn_name.to_string(), (rt.state.global_clk, depth)); - let padding = (0..depth).map(|_| "│ ").collect::(); - log::info!("{}┌╴{}", padding, fn_name); - } else if s.contains("cycle-tracker-end:") { - let fn_name = s - .split("cycle-tracker-end:") - .last() - .unwrap() - .trim_end() - .trim_start(); - let (start, depth) = rt.cycle_tracker.remove(fn_name).unwrap_or((0, 0)); - // Leftpad by 2 spaces for each depth. - let padding = (0..depth).map(|_| "│ ").collect::(); - log::info!( - "{}└╴{} cycles", - padding, - num_to_comma_separated(rt.state.global_clk - start as u64) - ); - } else { - let flush_s = update_io_buf(ctx, fd, s); - if !flush_s.is_empty() { - flush_s - .into_iter() - .for_each(|line| println!("stdout: {}", line)); - } - } - } else if fd == 2 { - let s = core::str::from_utf8(slice).unwrap(); - let flush_s = update_io_buf(ctx, fd, s); - if !flush_s.is_empty() { - flush_s - .into_iter() - .for_each(|line| println!("stderr: {}", line)); - } - } else if fd == 3 { - rt.state.public_values_stream.extend_from_slice(slice); - } else if fd == 4 { - rt.state.input_stream.push(slice.to_vec()); - } else if let Some(mut hook) = rt.hook_registry.get(&fd) { - let res = hook.invoke_hook(rt.hook_env(), slice); - // Add result vectors to the beginning of the stream. - let ptr = rt.state.input_stream_ptr; - rt.state.input_stream.splice(ptr..ptr, res); - } else { - log::warn!("tried to write to unknown file descriptor {fd}"); - } - None - } -} - -pub fn update_io_buf(ctx: &mut SyscallContext, fd: u32, s: &str) -> Vec { - let rt = &mut ctx.rt; - let entry = rt.io_buf.entry(fd).or_default(); - entry.push_str(s); - if entry.contains('\n') { - // Return lines except for the last from buf. - let prev_buf = std::mem::take(entry); - let mut lines = prev_buf.split('\n').collect::>(); - let last = lines.pop().unwrap_or(""); - *entry = last.to_string(); - lines - .into_iter() - .map(|line| line.to_string()) - .collect::>() - } else { - vec![] - } -} diff --git a/core/src/utils/config.rs b/core/src/utils/config.rs deleted file mode 100644 index 77e99c373a..0000000000 --- a/core/src/utils/config.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::stark::StarkGenericConfig; -use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; -use p3_challenger::DuplexChallenger; -use p3_commit::ExtensionMmcs; -use p3_dft::Radix2DitParallel; -use p3_field::{extension::BinomialExtensionField, Field}; -use p3_fri::BatchOpening; -use p3_fri::CommitPhaseProofStep; -use p3_fri::QueryProof; -use p3_fri::{FriConfig, FriProof, TwoAdicFriPcs, TwoAdicFriPcsProof}; -use p3_merkle_tree::FieldMerkleTreeMmcs; -use p3_poseidon2::Poseidon2; -use p3_poseidon2::Poseidon2ExternalMatrixGeneral; -use p3_symmetric::Hash; -use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; -use serde::Deserialize; -use serde::Serialize; -use sp1_primitives::poseidon2_init; - -pub const DIGEST_SIZE: usize = 8; - -/// A configuration for inner recursion. -pub type InnerVal = BabyBear; -pub type InnerChallenge = BinomialExtensionField; -pub type InnerPerm = - Poseidon2; -pub type InnerHash = PaddingFreeSponge; -pub type InnerDigestHash = Hash; -pub type InnerDigest = [InnerVal; DIGEST_SIZE]; -pub type InnerCompress = TruncatedPermutation; -pub type InnerValMmcs = FieldMerkleTreeMmcs< - ::Packing, - ::Packing, - InnerHash, - InnerCompress, - 8, ->; -pub type InnerChallengeMmcs = ExtensionMmcs; -pub type InnerChallenger = DuplexChallenger; -pub type InnerDft = Radix2DitParallel; -pub type InnerPcs = TwoAdicFriPcs; -pub type InnerQueryProof = QueryProof; -pub type InnerCommitPhaseStep = CommitPhaseProofStep; -pub type InnerFriProof = FriProof; -pub type InnerBatchOpening = BatchOpening; -pub type InnerPcsProof = - TwoAdicFriPcsProof; - -/// The permutation for inner recursion. -pub fn inner_perm() -> InnerPerm { - poseidon2_init() -} - -/// The FRI config for sp1 proofs. -pub fn sp1_fri_config() -> FriConfig { - let perm = inner_perm(); - let hash = InnerHash::new(perm.clone()); - let compress = InnerCompress::new(perm.clone()); - let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress)); - let num_queries = match std::env::var("FRI_QUERIES") { - Ok(value) => value.parse().unwrap(), - Err(_) => 100, - }; - FriConfig { - log_blowup: 1, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - } -} - -/// The FRI config for inner recursion. -pub fn inner_fri_config() -> FriConfig { - let perm = inner_perm(); - let hash = InnerHash::new(perm.clone()); - let compress = InnerCompress::new(perm.clone()); - let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress)); - let num_queries = match std::env::var("FRI_QUERIES") { - Ok(value) => value.parse().unwrap(), - Err(_) => 100, - }; - FriConfig { - log_blowup: 1, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - } -} - -/// The recursion config used for recursive reduce circuit. -#[derive(Deserialize)] -#[serde(from = "std::marker::PhantomData")] -pub struct BabyBearPoseidon2Inner { - pub perm: InnerPerm, - pub pcs: InnerPcs, -} - -impl Clone for BabyBearPoseidon2Inner { - fn clone(&self) -> Self { - Self::new() - } -} - -impl Serialize for BabyBearPoseidon2Inner { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - std::marker::PhantomData::.serialize(serializer) - } -} - -impl From> for BabyBearPoseidon2Inner { - fn from(_: std::marker::PhantomData) -> Self { - Self::new() - } -} - -impl BabyBearPoseidon2Inner { - pub fn new() -> Self { - let perm = inner_perm(); - let hash = InnerHash::new(perm.clone()); - let compress = InnerCompress::new(perm.clone()); - let val_mmcs = InnerValMmcs::new(hash, compress); - let dft = InnerDft {}; - let fri_config = inner_fri_config(); - let pcs = InnerPcs::new(27, dft, val_mmcs, fri_config); - Self { pcs, perm } - } -} - -impl Default for BabyBearPoseidon2Inner { - fn default() -> Self { - Self::new() - } -} - -impl StarkGenericConfig for BabyBearPoseidon2Inner { - type Val = InnerVal; - type Domain = >::Domain; - type Pcs = InnerPcs; - type Challenge = InnerChallenge; - type Challenger = InnerChallenger; - - fn pcs(&self) -> &Self::Pcs { - &self.pcs - } - - fn challenger(&self) -> Self::Challenger { - InnerChallenger::new(self.perm.clone()) - } -} diff --git a/core/src/utils/programs.rs b/core/src/utils/programs.rs deleted file mode 100644 index dada2735df..0000000000 --- a/core/src/utils/programs.rs +++ /dev/null @@ -1,104 +0,0 @@ -pub mod tests { - /// Demos. - - pub const CHESS_ELF: &[u8] = - include_bytes!("../../../examples/chess/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const FIBONACCI_IO_ELF: &[u8] = - include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const IO_ELF: &[u8] = - include_bytes!("../../../examples/io/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const JSON_ELF: &[u8] = - include_bytes!("../../../examples/json/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const REGEX_ELF: &[u8] = - include_bytes!("../../../examples/regex/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const RSA_ELF: &[u8] = - include_bytes!("../../../examples/rsa/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const SSZ_WITHDRAWALS_ELF: &[u8] = - include_bytes!("../../../examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf"); - - pub const TENDERMINT_ELF: &[u8] = - include_bytes!("../../../examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf"); - - /// Tests. - - pub const FIBONACCI_ELF: &[u8] = - include_bytes!("../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); - - pub const ED25519_ELF: &[u8] = - include_bytes!("../../../tests/ed25519/elf/riscv32im-succinct-zkvm-elf"); - - pub const CYCLE_TRACKER_ELF: &[u8] = - include_bytes!("../../../tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf"); - - pub const ECRECOVER_ELF: &[u8] = - include_bytes!("../../../tests/ecrecover/elf/riscv32im-succinct-zkvm-elf"); - - pub const ED_ADD_ELF: &[u8] = - include_bytes!("../../../tests/ed-add/elf/riscv32im-succinct-zkvm-elf"); - - pub const ED_DECOMPRESS_ELF: &[u8] = - include_bytes!("../../../tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf"); - - pub const KECCAK_PERMUTE_ELF: &[u8] = - include_bytes!("../../../tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf"); - - pub const KECCAK256_ELF: &[u8] = - include_bytes!("../../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf"); - - pub const SECP256K1_ADD_ELF: &[u8] = - include_bytes!("../../../tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf"); - - pub const SECP256K1_DECOMPRESS_ELF: &[u8] = - include_bytes!("../../../tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf"); - - pub const SECP256K1_DOUBLE_ELF: &[u8] = - include_bytes!("../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); - - pub const SHA_COMPRESS_ELF: &[u8] = - include_bytes!("../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); - - pub const SHA_EXTEND_ELF: &[u8] = - include_bytes!("../../../tests/sha-extend/elf/riscv32im-succinct-zkvm-elf"); - - pub const SHA2_ELF: &[u8] = - include_bytes!("../../../tests/sha2/elf/riscv32im-succinct-zkvm-elf"); - - pub const BN254_ADD_ELF: &[u8] = - include_bytes!("../../../tests/bn254-add/elf/riscv32im-succinct-zkvm-elf"); - - pub const BN254_DOUBLE_ELF: &[u8] = - include_bytes!("../../../tests/bn254-double/elf/riscv32im-succinct-zkvm-elf"); - - pub const BN254_MUL_ELF: &[u8] = - include_bytes!("../../../tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf"); - - pub const SECP256K1_MUL_ELF: &[u8] = - include_bytes!("../../../tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf"); - - pub const BLS12381_ADD_ELF: &[u8] = - include_bytes!("../../../tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf"); - - pub const BLS12381_DOUBLE_ELF: &[u8] = - include_bytes!("../../../tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf"); - - pub const BLS12381_MUL_ELF: &[u8] = - include_bytes!("../../../tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf"); - - pub const UINT256_MUL_ELF: &[u8] = - include_bytes!("../../../tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf"); - - pub const BLS12381_DECOMPRESS_ELF: &[u8] = - include_bytes!("../../../tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf"); - - pub const VERIFY_PROOF_ELF: &[u8] = - include_bytes!("../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); - - pub const PANIC_ELF: &[u8] = - include_bytes!("../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); -} diff --git a/build/CHANGELOG.md b/crates/build/CHANGELOG.md similarity index 100% rename from build/CHANGELOG.md rename to crates/build/CHANGELOG.md diff --git a/build/Cargo.toml b/crates/build/Cargo.toml similarity index 80% rename from build/Cargo.toml rename to crates/build/Cargo.toml index 5941dd3c02..b28b75d621 100644 --- a/build/Cargo.toml +++ b/crates/build/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "sp1-build" description = "Build an SP1 program." +readme = "README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -13,3 +14,4 @@ cargo_metadata = "0.18.1" anyhow = { version = "1.0.83" } clap = { version = "4.5.9", features = ["derive", "env"] } dirs = "5.0.1" +chrono = { version = "0.4.38", default-features = false, features = ["clock"] } diff --git a/build/README.md b/crates/build/README.md similarity index 93% rename from build/README.md rename to crates/build/README.md index cc7620417c..0e29481b77 100644 --- a/build/README.md +++ b/crates/build/README.md @@ -1,5 +1,5 @@ # sp1-build -Lightweight crate used to build SP1 programs. Internal crate that is exposed to users via `sp1-cli` and `sp1-helper`. +Lightweight crate used to build SP1 programs. Internal crate that is exposed to users via `sp1-cli`. Exposes `build_program`, which builds an SP1 program in the local environment or in a docker container with the specified parameters from `BuildArgs`. diff --git a/crates/build/src/build.rs b/crates/build/src/build.rs new file mode 100644 index 0000000000..e7a01b9d50 --- /dev/null +++ b/crates/build/src/build.rs @@ -0,0 +1,101 @@ +use std::path::PathBuf; + +use anyhow::Result; +use cargo_metadata::camino::Utf8PathBuf; + +use crate::{ + command::{docker::create_docker_command, local::create_local_command, utils::execute_command}, + utils::{cargo_rerun_if_changed, copy_elf_to_output_dir, current_datetime}, + BuildArgs, +}; + +/// Build a program with the specified [`BuildArgs`]. The `program_dir` is specified as an argument +/// when the program is built via `build_program`. +/// +/// # Arguments +/// +/// * `args` - A reference to a `BuildArgs` struct that holds various arguments used for building +/// the program. +/// * `program_dir` - An optional `PathBuf` specifying the directory of the program to be built. +/// +/// # Returns +/// +/// * `Result` - The path to the built program as a `Utf8PathBuf` on success, or an +/// error on failure. +pub fn execute_build_program( + args: &BuildArgs, + program_dir: Option, +) -> Result { + // If the program directory is not specified, use the current directory. + let program_dir = program_dir + .unwrap_or_else(|| std::env::current_dir().expect("Failed to get current directory.")); + let program_dir: Utf8PathBuf = + program_dir.try_into().expect("Failed to convert PathBuf to Utf8PathBuf"); + + // Get the program metadata. + let program_metadata_file = program_dir.join("Cargo.toml"); + let mut program_metadata_cmd = cargo_metadata::MetadataCommand::new(); + let program_metadata = + program_metadata_cmd.manifest_path(program_metadata_file).exec().unwrap(); + + // Get the command corresponding to Docker or local build. + let cmd = if args.docker { + create_docker_command(args, &program_dir, &program_metadata)? + } else { + create_local_command(args, &program_dir, &program_metadata) + }; + + execute_command(cmd, args.docker)?; + + copy_elf_to_output_dir(args, &program_metadata) +} + +/// Internal helper function to build the program with or without arguments. +pub(crate) fn build_program_internal(path: &str, args: Option) { + // Get the root package name and metadata. + let program_dir = std::path::Path::new(path); + let metadata_file = program_dir.join("Cargo.toml"); + let mut metadata_cmd = cargo_metadata::MetadataCommand::new(); + let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap(); + let root_package = metadata.root_package(); + let root_package_name = root_package.as_ref().map(|p| p.name.as_str()).unwrap_or("Program"); + + // Skip the program build if the SP1_SKIP_PROGRAM_BUILD environment variable is set to true. + let skip_program_build = std::env::var("SP1_SKIP_PROGRAM_BUILD") + .map(|v| v.eq_ignore_ascii_case("true")) + .unwrap_or(false); + if skip_program_build { + println!( + "cargo:warning=Build skipped for {} at {} due to SP1_SKIP_PROGRAM_BUILD flag", + root_package_name, + current_datetime() + ); + return; + } + + // Activate the build command if the dependencies change. + cargo_rerun_if_changed(&metadata, program_dir); + + // Check if RUSTC_WORKSPACE_WRAPPER is set to clippy-driver (i.e. if `cargo clippy` is the + // current compiler). If so, don't execute `cargo prove build` because it breaks + // rust-analyzer's `cargo clippy` feature. + let is_clippy_driver = std::env::var("RUSTC_WORKSPACE_WRAPPER") + .map(|val| val.contains("clippy-driver")) + .unwrap_or(false); + if is_clippy_driver { + println!("cargo:warning=Skipping build due to clippy invocation."); + return; + } + + // Build the program with the given arguments. + let path_output = if let Some(args) = args { + execute_build_program(&args, Some(program_dir.to_path_buf())) + } else { + execute_build_program(&BuildArgs::default(), Some(program_dir.to_path_buf())) + }; + if let Err(err) = path_output { + panic!("Failed to build SP1 program: {}.", err); + } + + println!("cargo:warning={} built at {}", root_package_name, current_datetime()); +} diff --git a/build/src/docker.rs b/crates/build/src/command/docker.rs similarity index 87% rename from build/src/docker.rs rename to crates/build/src/command/docker.rs index 618b618198..bd5ce5d23d 100644 --- a/build/src/docker.rs +++ b/crates/build/src/command/docker.rs @@ -3,7 +3,9 @@ use std::process::{exit, Command, Stdio}; use anyhow::{Context, Result}; use cargo_metadata::camino::Utf8PathBuf; -use crate::{get_program_build_args, get_rust_compiler_flags, BuildArgs}; +use crate::BuildArgs; + +use super::utils::{get_program_build_args, get_rust_compiler_flags}; /// Uses SP1_DOCKER_IMAGE environment variable if set, otherwise constructs the image to use based /// on the provided tag. @@ -15,7 +17,7 @@ fn get_docker_image(tag: &str) -> String { } /// Creates a Docker command to build the program. -pub fn create_docker_command( +pub(crate) fn create_docker_command( args: &BuildArgs, program_dir: &Utf8PathBuf, program_metadata: &cargo_metadata::Metadata, @@ -45,15 +47,12 @@ pub fn create_docker_command( let workspace_root_path = format!("{}:/root/program", workspace_root); let program_dir_path = format!( "/root/program/{}", - canonicalized_program_dir - .strip_prefix(workspace_root) - .unwrap() + canonicalized_program_dir.strip_prefix(workspace_root).unwrap() ); // Get the target directory for the ELF in the context of the Docker container. - let relative_target_dir = (program_metadata.target_directory) - .strip_prefix(workspace_root) - .unwrap(); + let relative_target_dir = + (program_metadata.target_directory).strip_prefix(workspace_root).unwrap(); let target_dir = format!( "/root/program/{}/{}/{}", relative_target_dir, @@ -62,7 +61,8 @@ pub fn create_docker_command( ); // When executing the Docker command: - // 1. Set the target directory to a subdirectory of the program's target directory to avoid build + // 1. Set the target directory to a subdirectory of the program's target directory to avoid + // build // conflicts with the parent process. Source: https://github.com/rust-lang/cargo/issues/6412 // 2. Set the rustup toolchain to succinct. // 3. Set the encoded rust flags. @@ -93,8 +93,6 @@ pub fn create_docker_command( docker_args.extend_from_slice(&get_program_build_args(args)); let mut command = Command::new("docker"); - command - .current_dir(canonicalized_program_dir.clone()) - .args(&docker_args); + command.current_dir(canonicalized_program_dir.clone()).args(&docker_args); Ok(command) } diff --git a/crates/build/src/command/local.rs b/crates/build/src/command/local.rs new file mode 100644 index 0000000000..47e129fd6c --- /dev/null +++ b/crates/build/src/command/local.rs @@ -0,0 +1,47 @@ +use std::{env, process::Command}; + +use crate::{BuildArgs, HELPER_TARGET_SUBDIR}; +use cargo_metadata::camino::Utf8PathBuf; +use dirs::home_dir; + +use super::utils::{get_program_build_args, get_rust_compiler_flags}; + +/// Get the command to build the program locally. +pub(crate) fn create_local_command( + args: &BuildArgs, + program_dir: &Utf8PathBuf, + program_metadata: &cargo_metadata::Metadata, +) -> Command { + let mut command = Command::new("cargo"); + let canonicalized_program_dir = + program_dir.canonicalize().expect("Failed to canonicalize program directory"); + + // If CC_riscv32im_succinct_zkvm_elf is not set, set it to the default C++ toolchain + // downloaded by 'sp1up --c-toolchain'. + if env::var("CC_riscv32im_succinct_zkvm_elf").is_err() { + if let Some(home_dir) = home_dir() { + let cc_path = home_dir.join(".sp1").join("bin").join("riscv32-unknown-elf-gcc"); + if cc_path.exists() { + command.env("CC_riscv32im_succinct_zkvm_elf", cc_path); + } + } + } + + // When executing the local command: + // 1. Set the target directory to a subdirectory of the program's target directory to avoid + // build + // conflicts with the parent process. Source: https://github.com/rust-lang/cargo/issues/6412 + // 2. Set the rustup toolchain to succinct. + // 3. Set the encoded rust flags. + // 4. Remove the rustc configuration, otherwise in a build script it will attempt to compile the + // program with the toolchain of the normal build process, rather than the Succinct + // toolchain. + command + .current_dir(canonicalized_program_dir) + .env("RUSTUP_TOOLCHAIN", "succinct") + .env("CARGO_ENCODED_RUSTFLAGS", get_rust_compiler_flags()) + .env_remove("RUSTC") + .env("CARGO_TARGET_DIR", program_metadata.target_directory.join(HELPER_TARGET_SUBDIR)) + .args(&get_program_build_args(args)); + command +} diff --git a/crates/build/src/command/mod.rs b/crates/build/src/command/mod.rs new file mode 100644 index 0000000000..bb305df16b --- /dev/null +++ b/crates/build/src/command/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod docker; +pub(crate) mod local; +pub(crate) mod utils; diff --git a/crates/build/src/command/utils.rs b/crates/build/src/command/utils.rs new file mode 100644 index 0000000000..014cb0e47f --- /dev/null +++ b/crates/build/src/command/utils.rs @@ -0,0 +1,92 @@ +use anyhow::{Context, Result}; +use std::{ + io::{BufRead, BufReader}, + process::{exit, Command, Stdio}, + thread, +}; + +use crate::{BuildArgs, BUILD_TARGET}; + +/// Get the arguments to build the program with the arguments from the [`BuildArgs`] struct. +pub(crate) fn get_program_build_args(args: &BuildArgs) -> Vec { + let mut build_args = vec![ + "build".to_string(), + "--release".to_string(), + "--target".to_string(), + BUILD_TARGET.to_string(), + ]; + + if args.ignore_rust_version { + build_args.push("--ignore-rust-version".to_string()); + } + + if !args.binary.is_empty() { + build_args.push("--bin".to_string()); + build_args.push(args.binary.clone()); + } + + if !args.features.is_empty() { + build_args.push("--features".to_string()); + build_args.push(args.features.join(",")); + } + + if args.no_default_features { + build_args.push("--no-default-features".to_string()); + } + + if args.locked { + build_args.push("--locked".to_string()); + } + + build_args +} + +/// Rust flags for compilation of C libraries. +pub(crate) fn get_rust_compiler_flags() -> String { + let rust_flags = [ + "-C".to_string(), + "passes=loweratomic".to_string(), + "-C".to_string(), + "link-arg=-Ttext=0x00200800".to_string(), + "-C".to_string(), + "panic=abort".to_string(), + ]; + rust_flags.join("\x1f") +} + +/// Execute the command and handle the output depending on the context. +pub(crate) fn execute_command(mut command: Command, docker: bool) -> Result<()> { + // Add necessary tags for stdout and stderr from the command. + let mut child = command + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("failed to spawn command")?; + let stdout = BufReader::new(child.stdout.take().unwrap()); + let stderr = BufReader::new(child.stderr.take().unwrap()); + + // Add prefix to the output of the process depending on the context. + let msg = match docker { + true => "[sp1] [docker] ", + false => "[sp1] ", + }; + + // Pipe stdout and stderr to the parent process with [docker] prefix + let stdout_handle = thread::spawn(move || { + stdout.lines().for_each(|line| { + println!("{} {}", msg, line.unwrap()); + }); + }); + stderr.lines().for_each(|line| { + eprintln!("{} {}", msg, line.unwrap()); + }); + stdout_handle.join().unwrap(); + + // Wait for the child process to finish and check the result. + let result = child.wait()?; + if !result.success() { + // Error message is already printed by cargo. + exit(result.code().unwrap_or(1)) + } + Ok(()) +} diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs new file mode 100644 index 0000000000..89731cc864 --- /dev/null +++ b/crates/build/src/lib.rs @@ -0,0 +1,111 @@ +mod build; +mod command; +mod utils; +use build::build_program_internal; +pub use build::execute_build_program; + +use clap::Parser; + +const BUILD_TARGET: &str = "riscv32im-succinct-zkvm-elf"; +const DEFAULT_TAG: &str = "v1.1.0"; +const DEFAULT_OUTPUT_DIR: &str = "elf"; +const HELPER_TARGET_SUBDIR: &str = "elf-compilation"; + +/// Compile an SP1 program. +/// +/// Additional arguments are useful for configuring the build process, including options for using +/// Docker, specifying binary and ELF names, ignoring Rust version checks, and enabling specific +/// features. +#[derive(Clone, Parser, Debug)] +pub struct BuildArgs { + #[clap( + long, + action, + help = "Run compilation using a Docker container for reproducible builds." + )] + pub docker: bool, + #[clap( + long, + help = "The ghcr.io/succinctlabs/sp1 image tag to use when building with Docker.", + default_value = DEFAULT_TAG + )] + pub tag: String, + #[clap( + long, + action, + value_delimiter = ',', + help = "Space or comma separated list of features to activate" + )] + pub features: Vec, + #[clap(long, action, help = "Do not activate the `default` feature")] + pub no_default_features: bool, + #[clap(long, action, help = "Ignore `rust-version` specification in packages")] + pub ignore_rust_version: bool, + #[clap(long, action, help = "Assert that `Cargo.lock` will remain unchanged")] + pub locked: bool, + #[clap( + alias = "bin", + long, + action, + help = "Build only the specified binary", + default_value = "" + )] + pub binary: String, + #[clap(long, action, help = "ELF binary name", default_value = "")] + pub elf_name: String, + #[clap( + alias = "out-dir", + long, + action, + help = "Copy the compiled ELF to this directory", + default_value = DEFAULT_OUTPUT_DIR + )] + pub output_directory: String, +} + +// Implement default args to match clap defaults. +impl Default for BuildArgs { + fn default() -> Self { + Self { + docker: false, + tag: DEFAULT_TAG.to_string(), + features: vec![], + ignore_rust_version: false, + binary: "".to_string(), + elf_name: "".to_string(), + output_directory: DEFAULT_OUTPUT_DIR.to_string(), + locked: false, + no_default_features: false, + } + } +} + +/// Builds the program if the program at the specified path, or one of its dependencies, changes. +/// +/// This function monitors the program and its dependencies for changes. If any changes are +/// detected, it triggers a rebuild of the program. +/// +/// # Arguments +/// +/// * `path` - A string slice that holds the path to the program directory. +/// +/// This function is useful for automatically rebuilding the program during development +/// when changes are made to the source code or its dependencies. +/// +/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program. +pub fn build_program(path: &str) { + build_program_internal(path, None) +} + +/// Builds the program with the given arguments if the program at path, or one of its dependencies, +/// changes. +/// +/// # Arguments +/// +/// * `path` - A string slice that holds the path to the program directory. +/// * `args` - A [`BuildArgs`] struct that contains various build configuration options. +/// +/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program. +pub fn build_program_with_args(path: &str, args: BuildArgs) { + build_program_internal(path, Some(args)) +} diff --git a/crates/build/src/utils.rs b/crates/build/src/utils.rs new file mode 100644 index 0000000000..72af0da115 --- /dev/null +++ b/crates/build/src/utils.rs @@ -0,0 +1,88 @@ +use std::{fs, path::Path}; + +use anyhow::Result; +use cargo_metadata::{camino::Utf8PathBuf, Metadata}; +use chrono::Local; + +use crate::{BuildArgs, BUILD_TARGET, HELPER_TARGET_SUBDIR}; + +/// Copy the ELF to the specified output directory. +pub(crate) fn copy_elf_to_output_dir( + args: &BuildArgs, + program_metadata: &cargo_metadata::Metadata, +) -> Result { + let root_package = program_metadata.root_package(); + let root_package_name = root_package.as_ref().map(|p| &p.name); + + // The ELF is written to a target folder specified by the program's package. If built with + // Docker, includes /docker after HELPER_TARGET_SUBDIR. + let target_dir_suffix = if args.docker { + format!("{}/{}", HELPER_TARGET_SUBDIR, "docker") + } else { + HELPER_TARGET_SUBDIR.to_string() + }; + + let original_elf_path = program_metadata + .target_directory + .join(target_dir_suffix) + .join(BUILD_TARGET) + .join("release") + .join(root_package_name.unwrap()); + + // The order of precedence for the ELF name is: + // 1. --elf_name flag + // 2. --binary flag + -elf suffix (defaults to riscv32im-succinct-zkvm-elf) + let elf_name = if !args.elf_name.is_empty() { + args.elf_name.clone() + } else if !args.binary.is_empty() { + // TODO: In the future, change this to default to the package name. Will require updating + // docs and examples. + args.binary.clone() + } else { + BUILD_TARGET.to_string() + }; + + let elf_dir = program_metadata.target_directory.parent().unwrap().join(&args.output_directory); + fs::create_dir_all(&elf_dir)?; + let result_elf_path = elf_dir.join(elf_name); + + // Copy the ELF to the specified output directory. + fs::copy(original_elf_path, &result_elf_path)?; + + Ok(result_elf_path) +} + +pub(crate) fn current_datetime() -> String { + let now = Local::now(); + now.format("%Y-%m-%d %H:%M:%S").to_string() +} + +/// Re-run the cargo command if the Cargo.toml or Cargo.lock file changes. +pub(crate) fn cargo_rerun_if_changed(metadata: &Metadata, program_dir: &Path) { + // Tell cargo to rerun the script only if program/{src, bin, build.rs, Cargo.toml} changes + // Ref: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rerun-if-changed + let dirs = vec![ + program_dir.join("src"), + program_dir.join("bin"), + program_dir.join("build.rs"), + program_dir.join("Cargo.toml"), + ]; + for dir in dirs { + if dir.exists() { + println!("cargo::rerun-if-changed={}", dir.canonicalize().unwrap().display()); + } + } + + // Re-run the build script if the workspace root's Cargo.lock changes. If the program is its own + // workspace, this will be the program's Cargo.lock. + println!("cargo:rerun-if-changed={}", metadata.workspace_root.join("Cargo.lock").as_str()); + + // Re-run if any local dependency changes. + for package in &metadata.packages { + for dependency in &package.dependencies { + if let Some(path) = &dependency.path { + println!("cargo:rerun-if-changed={}", path.as_str()); + } + } + } +} diff --git a/cli/CHANGELOG.md b/crates/cli/CHANGELOG.md similarity index 100% rename from cli/CHANGELOG.md rename to crates/cli/CHANGELOG.md diff --git a/cli/Cargo.toml b/crates/cli/Cargo.toml similarity index 85% rename from cli/Cargo.toml rename to crates/cli/Cargo.toml index 902acee44b..3ccce01986 100644 --- a/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-cli" -description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +description = "The CLI is used for various tasks related to SP1, such as building the toolchain, compiling programs, and tracing programs." +readme = "README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -24,7 +24,7 @@ clap = { version = "4.5.9", features = ["derive", "env"] } sp1-build = { workspace = true } sp1-prover = { workspace = true } sp1-sdk = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } reqwest = { version = "0.12.4", features = [ "stream", "json", diff --git a/cli/README.md b/crates/cli/README.md similarity index 99% rename from cli/README.md rename to crates/cli/README.md index 94ee71fb47..30e8f31596 100644 --- a/cli/README.md +++ b/crates/cli/README.md @@ -11,6 +11,7 @@ cargo run --bin cargo-prove -- --help ``` To test a particular subcommand, you can pass in `prove` and the subcommand you want to test along with the arguments you want to pass to it. For example, to test the `trace` subcommand, you can run the following command: + ```bash cargo run --bin cargo-prove -- prove trace --elf <...> --trace <...> ``` diff --git a/crates/cli/build.rs b/crates/cli/build.rs new file mode 100644 index 0000000000..c2f550fb6f --- /dev/null +++ b/crates/cli/build.rs @@ -0,0 +1,3 @@ +fn main() { + vergen::EmitBuilder::builder().build_timestamp().git_sha(true).emit().unwrap(); +} diff --git a/crates/cli/docker/Dockerfile b/crates/cli/docker/Dockerfile new file mode 100644 index 0000000000..8748b5aee7 --- /dev/null +++ b/crates/cli/docker/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:24.04@sha256:e3f92abc0967a6c19d0dfa2d55838833e947b9d74edbcb0113e48535ad4be12a + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates clang curl libssl-dev pkg-config git dialog xz-utils \ + && curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL 'https://sh.rustup.rs' | sh -s -- -y + +ENV PATH="/root/.cargo/bin:${PATH}" + +ARG BUILDTIME + +# Use the BUILDTIME argument to break caching and force a new layer +RUN echo "Cache bust: ${BUILDTIME}" > /dev/null && \ + curl -L https://sp1.succinct.xyz | bash && ~/.sp1/bin/sp1up --c-toolchain + +WORKDIR /root/program + +ENV CARGO_TERM_COLOR=always +ENTRYPOINT [ "/root/.sp1/bin/cargo-prove" ] +CMD [ "prove" ] \ No newline at end of file diff --git a/cli/src/bin/cargo-prove.rs b/crates/cli/src/bin/cargo-prove.rs similarity index 93% rename from cli/src/bin/cargo-prove.rs rename to crates/cli/src/bin/cargo-prove.rs index af04ebaffc..56f452e708 100644 --- a/cli/src/bin/cargo-prove.rs +++ b/crates/cli/src/bin/cargo-prove.rs @@ -4,6 +4,7 @@ use sp1_cli::{ commands::{ build::BuildCmd, build_toolchain::BuildToolchainCmd, install_toolchain::InstallToolchainCmd, new::NewCmd, prove::ProveCmd, trace::TraceCmd, + vkey::VkeyCmd, }, SP1_VERSION_MESSAGE, }; @@ -32,6 +33,7 @@ pub enum ProveCliCommands { BuildToolchain(BuildToolchainCmd), InstallToolchain(InstallToolchainCmd), Trace(TraceCmd), + Vkey(VkeyCmd), } fn main() -> Result<()> { @@ -44,5 +46,6 @@ fn main() -> Result<()> { ProveCliCommands::BuildToolchain(cmd) => cmd.run(), ProveCliCommands::InstallToolchain(cmd) => cmd.run(), ProveCliCommands::Trace(cmd) => cmd.run(), + ProveCliCommands::Vkey(cmd) => cmd.run(), } } diff --git a/cli/src/commands/build.rs b/crates/cli/src/commands/build.rs similarity index 71% rename from cli/src/commands/build.rs rename to crates/cli/src/commands/build.rs index d72504c954..e5f539e429 100644 --- a/cli/src/commands/build.rs +++ b/crates/cli/src/commands/build.rs @@ -1,6 +1,6 @@ use anyhow::Result; use clap::Parser; -use sp1_build::{build_program, BuildArgs}; +use sp1_build::{execute_build_program, BuildArgs}; #[derive(Parser)] #[command(name = "build", about = "Compile an SP1 program")] @@ -11,7 +11,7 @@ pub struct BuildCmd { impl BuildCmd { pub fn run(&self) -> Result<()> { - build_program(&self.build_args, None)?; + execute_build_program(&self.build_args, None)?; Ok(()) } diff --git a/cli/src/commands/build_toolchain.rs b/crates/cli/src/commands/build_toolchain.rs similarity index 87% rename from cli/src/commands/build_toolchain.rs rename to crates/cli/src/commands/build_toolchain.rs index 8b921221ae..86a604d128 100644 --- a/cli/src/commands/build_toolchain.rs +++ b/crates/cli/src/commands/build_toolchain.rs @@ -31,10 +31,7 @@ impl BuildToolchainCmd { let repo_url = match github_access_token { Ok(github_access_token) => { println!("Detected GITHUB_ACCESS_TOKEN, using it to clone rust."); - format!( - "https://{}@github.com/succinctlabs/rust", - github_access_token - ) + format!("https://{}@github.com/succinctlabs/rust", github_access_token) } Err(_) => { println!("No GITHUB_ACCESS_TOKEN detected. If you get throttled by Github, set it to bypass the rate limit."); @@ -52,10 +49,7 @@ impl BuildToolchainCmd { ]) .current_dir(&temp_dir) .run()?; - Command::new("git") - .args(["reset", "--hard"]) - .current_dir(&dir) - .run()?; + Command::new("git").args(["reset", "--hard"]).current_dir(&dir).run()?; Command::new("git") .args(["submodule", "update", "--init", "--recursive", "--progress"]) .current_dir(&dir) @@ -72,29 +66,20 @@ impl BuildToolchainCmd { // Build the toolchain (stage 1). Command::new("python3") - .env( - "CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", - "-Cpasses=loweratomic", - ) + .env("CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", "-Cpasses=loweratomic") .args(["x.py", "build"]) .current_dir(&rust_dir) .run()?; // Build the toolchain (stage 2). Command::new("python3") - .env( - "CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", - "-Cpasses=loweratomic", - ) + .env("CARGO_TARGET_RISCV32IM_SUCCINCT_ZKVM_ELF_RUSTFLAGS", "-Cpasses=loweratomic") .args(["x.py", "build", "--stage", "2"]) .current_dir(&rust_dir) .run()?; // Remove the existing toolchain from rustup, if it exists. - match Command::new("rustup") - .args(["toolchain", "remove", RUSTUP_TOOLCHAIN_NAME]) - .run() - { + match Command::new("rustup").args(["toolchain", "remove", RUSTUP_TOOLCHAIN_NAME]).run() { Ok(_) => println!("Successfully removed existing toolchain."), Err(_) => println!("No existing toolchain to remove."), } diff --git a/cli/src/commands/config.toml b/crates/cli/src/commands/config.toml similarity index 100% rename from cli/src/commands/config.toml rename to crates/cli/src/commands/config.toml diff --git a/cli/src/commands/install_toolchain.rs b/crates/cli/src/commands/install_toolchain.rs similarity index 90% rename from cli/src/commands/install_toolchain.rs rename to crates/cli/src/commands/install_toolchain.rs index 6daaab5500..de09773cef 100644 --- a/cli/src/commands/install_toolchain.rs +++ b/crates/cli/src/commands/install_toolchain.rs @@ -4,9 +4,11 @@ use dirs::home_dir; use rand::{distributions::Alphanumeric, Rng}; use reqwest::Client; use sp1_sdk::artifacts::download_file; -use std::fs::{self}; -use std::io::Read; -use std::process::Command; +use std::{ + fs::{self}, + io::Read, + process::Command, +}; #[cfg(target_family = "unix")] use std::os::unix::fs::PermissionsExt; @@ -16,10 +18,7 @@ use crate::{ }; #[derive(Parser)] -#[command( - name = "install-toolchain", - about = "Install the cargo-prove toolchain." -)] +#[command(name = "install-toolchain", about = "Install the cargo-prove toolchain.")] pub struct InstallToolchainCmd { #[arg(short, long, env = "GITHUB_TOKEN")] pub token: Option, @@ -114,12 +113,7 @@ impl InstallToolchainCmd { // Download the toolchain. let mut file = fs::File::create(toolchain_archive_path)?; - rt.block_on(download_file( - &client, - toolchain_download_url.as_str(), - &mut file, - )) - .unwrap(); + rt.block_on(download_file(&client, toolchain_download_url.as_str(), &mut file)).unwrap(); // Remove the existing toolchain from rustup, if it exists. let mut child = Command::new("rustup") @@ -144,22 +138,14 @@ impl InstallToolchainCmd { fs::create_dir_all(toolchain_dir.clone())?; Command::new("tar") .current_dir(&root_dir) - .args([ - "-xzf", - &toolchain_asset_name, - "-C", - &toolchain_dir.to_string_lossy(), - ]) + .args(["-xzf", &toolchain_asset_name, "-C", &toolchain_dir.to_string_lossy()]) .status()?; // Move the toolchain to a randomly named directory in the 'toolchains' folder let toolchains_dir = root_dir.join("toolchains"); fs::create_dir_all(&toolchains_dir)?; - let random_string: String = rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(10) - .map(char::from) - .collect(); + let random_string: String = + rand::thread_rng().sample_iter(&Alphanumeric).take(10).map(char::from).collect(); let new_toolchain_dir = toolchains_dir.join(random_string); fs::rename(&toolchain_dir, &new_toolchain_dir)?; diff --git a/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs similarity index 88% rename from cli/src/commands/mod.rs rename to crates/cli/src/commands/mod.rs index d3a429d0f4..af62dcf36e 100644 --- a/cli/src/commands/mod.rs +++ b/crates/cli/src/commands/mod.rs @@ -4,3 +4,4 @@ pub mod install_toolchain; pub mod new; pub mod prove; pub mod trace; +pub mod vkey; diff --git a/cli/src/commands/new.rs b/crates/cli/src/commands/new.rs similarity index 89% rename from cli/src/commands/new.rs rename to crates/cli/src/commands/new.rs index d7d959749d..3272600aab 100644 --- a/cli/src/commands/new.rs +++ b/crates/cli/src/commands/new.rs @@ -29,11 +29,7 @@ impl NewCmd { fs::create_dir(&self.name)?; } - println!( - " \x1b[1m{}\x1b[0m {}", - Paint::green("Cloning"), - TEMPLATE_REPOSITORY_URL - ); + println!(" \x1b[1m{}\x1b[0m {}", Paint::green("Cloning"), TEMPLATE_REPOSITORY_URL); // Clone the repository with the specified version. let output = Command::new("git") @@ -74,10 +70,7 @@ impl NewCmd { " \x1b[1m{}\x1b[0m {} ({})", Paint::green("Initialized"), self.name, - std::fs::canonicalize(root) - .expect("failed to canonicalize") - .to_str() - .unwrap() + std::fs::canonicalize(root).expect("failed to canonicalize").to_str().unwrap() ); Ok(()) diff --git a/cli/src/commands/prove.rs b/crates/cli/src/commands/prove.rs similarity index 82% rename from cli/src/commands/prove.rs rename to crates/cli/src/commands/prove.rs index 72eea0b5ee..0e2951dc23 100644 --- a/cli/src/commands/prove.rs +++ b/crates/cli/src/commands/prove.rs @@ -1,12 +1,13 @@ use anstyle::*; use anyhow::Result; use clap::Parser; -use sp1_build::{build_program, BuildArgs}; -use sp1_core::utils::{setup_logger, setup_tracer}; -use sp1_prover::SP1Stdin; +use sp1_build::{execute_build_program, BuildArgs}; +use sp1_core_machine::{ + io::SP1Stdin, + utils::{setup_logger, setup_tracer}, +}; use sp1_sdk::ProverClient; -use std::time::Instant; -use std::{env, fs::File, io::Read, path::PathBuf, str::FromStr}; +use std::{env, fs::File, io::Read, path::PathBuf, str::FromStr, time::Instant}; use crate::util::{elapsed, write_status}; @@ -31,11 +32,7 @@ impl FromStr for Input { fn from_str(s: &str) -> Result { if is_valid_hex_string(s) { // Remove 0x prefix if present - let s = if s.starts_with("0x") { - s.strip_prefix("0x").unwrap() - } else { - s - }; + let s = if s.starts_with("0x") { s.strip_prefix("0x").unwrap() } else { s }; if s.is_empty() { return Ok(Input::HexBytes(Vec::new())); } @@ -73,7 +70,7 @@ pub struct ProveCmd { impl ProveCmd { pub fn run(&self) -> Result<()> { - let elf_path = build_program(&self.build_args, None)?; + let elf_path = execute_build_program(&self.build_args, None)?; if !self.profile { match env::var("RUST_LOG") { @@ -116,18 +113,12 @@ impl ProveCmd { let proof = client.prove(&pk, stdin).run().unwrap(); if let Some(ref path) = self.output { - proof - .save(path.to_str().unwrap()) - .expect("failed to save proof"); + proof.save(path.to_str().unwrap()).expect("failed to save proof"); } let elapsed = elapsed(start_time.elapsed()); let green = AnsiColor::Green.on_default().effects(Effects::BOLD); - write_status( - &green, - "Finished", - format!("proving in {}", elapsed).as_str(), - ); + write_status(&green, "Finished", format!("proving in {}", elapsed).as_str()); Ok(()) } diff --git a/cli/src/commands/trace.rs b/crates/cli/src/commands/trace.rs similarity index 87% rename from cli/src/commands/trace.rs rename to crates/cli/src/commands/trace.rs index 25add79789..9c5e6d3418 100644 --- a/cli/src/commands/trace.rs +++ b/crates/cli/src/commands/trace.rs @@ -1,5 +1,6 @@ //! RISC-V tracer for SP1 traces. This tool can be used to analyze function call graphs and -//! instruction counts from a trace file from SP1 execution by setting the `TRACE_FILE` env variable. +//! instruction counts from a trace file from SP1 execution by setting the `TRACE_FILE` env +//! variable. // // Adapted from Sovereign's RISC-V tracer tool: https://github.com/Sovereign-Labs/riscv-cycle-tracer. // @@ -24,20 +25,18 @@ use indicatif::{ProgressBar, ProgressStyle}; use prettytable::{format, Cell, Row, Table}; use regex::Regex; use rustc_demangle::demangle; -use std::cmp::Ordering; -use std::collections::HashMap; -use std::io::Read; -use std::process::Command; -use std::str; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; +use std::{ + cmp::Ordering, + collections::HashMap, + io::Read, + process::Command, + str, + sync::{atomic::AtomicBool, Arc}, +}; use textwrap::wrap; #[derive(Parser, Debug)] -#[command( - name = "trace", - about = "Trace a program execution and analyze cycle counts." -)] +#[command(name = "trace", about = "Trace a program execution and analyze cycle counts.")] pub struct TraceCmd { /// Include the "top" number of functions. #[arg(short, long, default_value_t = 30)] @@ -96,10 +95,7 @@ fn print_intruction_counts( ) { let mut table = Table::new(); table.set_format(*format::consts::FORMAT_NO_LINESEP); - table.set_titles(Row::new(vec![ - Cell::new(first_header), - Cell::new("Instruction Count"), - ])); + table.set_titles(Row::new(vec![Cell::new(first_header), Cell::new("Instruction Count")])); let wrap_width = 120; let mut row_count = 0; @@ -126,10 +122,7 @@ fn print_intruction_counts( } let wrapped_key = wrap(&stripped_key, wrap_width); let key_cell_content = wrapped_key.join("\n"); - table.add_row(Row::new(vec![ - Cell::new(&key_cell_content), - Cell::new(&value.to_string()), - ])); + table.add_row(Row::new(vec![Cell::new(&key_cell_content), Cell::new(&value.to_string())])); } table.printstd(); @@ -143,9 +136,7 @@ fn focused_stack_counts( ) { if let Some(index) = function_stack.iter().position(|s| s == function_name) { let truncated_stack = &function_stack[0..=index]; - let count = filtered_stack_counts - .entry(truncated_stack.to_vec()) - .or_insert(0); + let count = filtered_stack_counts.entry(truncated_stack.to_vec()).or_insert(0); *count += num_instructions; } } @@ -156,12 +147,7 @@ fn _build_radare2_lookups( func_range_lookup: &mut HashMap, elf_name: &str, ) -> std::io::Result<()> { - let output = Command::new("r2") - .arg("-q") - .arg("-c") - .arg("aa;afl") - .arg(elf_name) - .output()?; + let output = Command::new("r2").arg("-q").arg("-c").arg("aa;afl").arg(elf_name).output()?; if output.status.success() { let result_str = str::from_utf8(&output.stdout).unwrap(); @@ -176,10 +162,7 @@ fn _build_radare2_lookups( func_range_lookup.insert(function_name.to_string(), (address, end_address)); } } else { - eprintln!( - "Error executing command: {}", - str::from_utf8(&output.stderr).unwrap() - ); + eprintln!("Error executing command: {}", str::from_utf8(&output.stderr).unwrap()); } Ok(()) } @@ -237,18 +220,11 @@ impl TraceCmd { let mut start_lookup = HashMap::new(); let mut end_lookup = HashMap::new(); let mut func_range_lookup = HashMap::new(); - build_goblin_lookups( - &mut start_lookup, - &mut end_lookup, - &mut func_range_lookup, - &elf_path, - ) - .unwrap(); - - let mut function_ranges: Vec<(u64, u64, String)> = func_range_lookup - .iter() - .map(|(f, &(start, end))| (start, end, f.clone())) - .collect(); + build_goblin_lookups(&mut start_lookup, &mut end_lookup, &mut func_range_lookup, &elf_path) + .unwrap(); + + let mut function_ranges: Vec<(u64, u64, String)> = + func_range_lookup.iter().map(|(f, &(start, end))| (start, end, f.clone())).collect(); function_ranges.sort_by_key(|&(start, _, _)| start); @@ -313,9 +289,8 @@ impl TraceCmd { let (_, _, fname) = &function_ranges[index]; *counts_without_callgraph.entry(fname.clone()).or_insert(0) += num_instructions } else { - *counts_without_callgraph - .entry("anonymous".to_string()) - .or_insert(0) += num_instructions; + *counts_without_callgraph.entry("anonymous".to_string()).or_insert(0) += + num_instructions; } // The next section considers the callstack. We build a callstack and maintain it based @@ -395,10 +370,8 @@ impl TraceCmd { pb.finish_with_message("done"); - let mut raw_counts: Vec<(String, usize)> = instruction_counts - .iter() - .map(|(key, value)| (key.clone(), *value)) - .collect(); + let mut raw_counts: Vec<(String, usize)> = + instruction_counts.iter().map(|(key, value)| (key.clone(), *value)).collect(); raw_counts.sort_by(|a, b| b.1.cmp(&a.1)); println!("\n\nTotal instructions in trace: {}", total_lines); @@ -413,10 +386,8 @@ impl TraceCmd { ); } - let mut raw_counts: Vec<(String, usize)> = counts_without_callgraph - .iter() - .map(|(key, value)| (key.clone(), *value)) - .collect(); + let mut raw_counts: Vec<(String, usize)> = + counts_without_callgraph.iter().map(|(key, value)| (key.clone(), *value)).collect(); raw_counts.sort_by(|a, b| b.1.cmp(&a.1)); if !no_raw_counts { println!("\n\n Instruction counts ignoring call graph"); @@ -437,11 +408,8 @@ impl TraceCmd { .rev() .enumerate() .map(|(index, line)| { - let modified_line = if strip_hashes { - strip_hash(line) - } else { - line.clone() - }; + let modified_line = + if strip_hashes { strip_hash(line) } else { line.clone() }; format!("({}) {}", index + 1, modified_line) }) .collect::>() diff --git a/crates/cli/src/commands/vkey.rs b/crates/cli/src/commands/vkey.rs new file mode 100644 index 0000000000..58fd64e3d7 --- /dev/null +++ b/crates/cli/src/commands/vkey.rs @@ -0,0 +1,33 @@ +use std::fs::File; + +use anyhow::Result; +use clap::Parser; +use sp1_sdk::HashableKey; +use sp1_sdk::ProverClient; +use std::io::Read; + +#[derive(Parser)] +#[command(name = "vkey", about = "View the verification key hash for a program.")] +pub struct VkeyCmd { + /// Path to the ELF. + #[arg(long, required = true)] + elf: String, +} + +impl VkeyCmd { + pub fn run(&self) -> Result<()> { + // Read the elf file contents + let mut file = File::open(self.elf.clone()).unwrap(); + let mut elf = Vec::new(); + file.read_to_end(&mut elf).unwrap(); + + // Get the verification key + let prover = ProverClient::new(); + let (_, vk) = prover.setup(&elf); + + // Print the verification key hash + println!("Verification Key Hash:\n{}", vk.vk.bytes32()); + + Ok(()) + } +} diff --git a/cli/src/lib.rs b/crates/cli/src/lib.rs similarity index 92% rename from cli/src/lib.rs rename to crates/cli/src/lib.rs index 654f7fab93..c9762921be 100644 --- a/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -7,14 +7,8 @@ use std::process::{Command, Stdio}; pub const RUSTUP_TOOLCHAIN_NAME: &str = "succinct"; -pub const SP1_VERSION_MESSAGE: &str = concat!( - "sp1", - " (", - env!("VERGEN_GIT_SHA"), - " ", - env!("VERGEN_BUILD_TIMESTAMP"), - ")" -); +pub const SP1_VERSION_MESSAGE: &str = + concat!("sp1", " (", env!("VERGEN_GIT_SHA"), " ", env!("VERGEN_BUILD_TIMESTAMP"), ")"); trait CommandExecutor { fn run(&mut self) -> Result<()>; diff --git a/cli/src/util.rs b/crates/cli/src/util.rs similarity index 100% rename from cli/src/util.rs rename to crates/cli/src/util.rs diff --git a/crates/core/executor/CHANGELOG.md b/crates/core/executor/CHANGELOG.md new file mode 100644 index 0000000000..b413fc23d6 --- /dev/null +++ b/crates/core/executor/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-core-executor-v1.2.0-rc1) - 2024-08-23 + +### Added + +- gas ([#1354](https://github.com/succinctlabs/sp1/pull/1354)) + +### Fixed + +- fix artifact export test +- fix fptower tests +- fix imports +- cargo check on tests + +### Other + +- runtime optimizations ([#1344](https://github.com/succinctlabs/sp1/pull/1344)) +- make state pub ([#1345](https://github.com/succinctlabs/sp1/pull/1345)) +- resolve merge conflicts between dev and experimental +- refactor + cleanup core crates diff --git a/crates/core/executor/Cargo.toml b/crates/core/executor/Cargo.toml new file mode 100644 index 0000000000..4834fbcf6d --- /dev/null +++ b/crates/core/executor/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "sp1-core-executor" +description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." +readme = "../../../README.md" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } + +[dependencies] +# sp1 +sp1-primitives = { workspace = true } +sp1-curves = { workspace = true } +sp1-stark = { workspace = true } +sp1-derive = { workspace = true } + +# p3 +p3-keccak-air = { workspace = true } +p3-field = { workspace = true } +p3-maybe-rayon = { workspace = true, features = ["parallel"] } + +# misc +serde = { version = "1.0.205", features = ["derive", "rc"] } +elf = "0.7.4" +rrs_lib = { package = "rrs-succinct", version = "0.1.0" } +eyre = "0.6.12" +serde_with = "3.9.0" +bincode = "1.3.3" +hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] } +itertools = "0.13.0" +rand = "0.8.5" +generic-array = { version = "1.1.0", features = ["alloc", "serde"] } +num = { version = "0.4.3" } +typenum = "1.17.0" +nohash-hasher = "0.2.0" +thiserror = "1.0.63" +tracing = "0.1.40" +strum_macros = "0.26.4" +strum = "0.26.3" +log = "0.4.22" +hex = "0.4.3" +bytemuck = "1.16.3" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } + +[dev-dependencies] +sp1-zkvm = { workspace = true } + +[features] +programs = [] diff --git a/core/src/runtime/context.rs b/crates/core/executor/src/context.rs similarity index 80% rename from core/src/runtime/context.rs rename to crates/core/executor/src/context.rs index d2642f4228..4c8c535aaf 100644 --- a/core/src/runtime/context.rs +++ b/crates/core/executor/src/context.rs @@ -1,7 +1,12 @@ use core::mem::take; use std::sync::Arc; -use super::{hookify, BoxedHook, HookEnv, HookRegistry, SubproofVerifier}; +use hashbrown::HashMap; + +use crate::{ + hook::{hookify, BoxedHook, HookEnv, HookRegistry}, + subproof::SubproofVerifier, +}; /// Context to run a program inside SP1. #[derive(Clone, Default)] @@ -18,6 +23,7 @@ pub struct SP1Context<'a> { pub max_cycles: Option, } +/// A builder for [`SP1Context`]. #[derive(Clone, Default)] pub struct SP1ContextBuilder<'a> { no_default_hooks: bool, @@ -27,7 +33,8 @@ pub struct SP1ContextBuilder<'a> { } impl<'a> SP1Context<'a> { - /// Create a new context builder. See [SP1ContextBuilder] for more details. + /// Create a new context builder. See [`SP1ContextBuilder`] for more details. + #[must_use] pub fn builder() -> SP1ContextBuilder<'a> { SP1ContextBuilder::new() } @@ -37,11 +44,12 @@ impl<'a> SP1ContextBuilder<'a> { /// Create a new [`SP1ContextBuilder`]. /// /// Prefer using [`SP1Context::builder`]. + #[must_use] pub fn new() -> Self { - Default::default() + SP1ContextBuilder::default() } - /// Build and return the [SP1Context]. + /// Build and return the [`SP1Context`]. /// /// Clears and resets the builder, allowing it to be reused. pub fn build(&mut self) -> SP1Context<'a> { @@ -50,7 +58,7 @@ impl<'a> SP1ContextBuilder<'a> { let hook_registry = (!self.hook_registry_entries.is_empty() || self.no_default_hooks).then(|| { let mut table = if take(&mut self.no_default_hooks) { - Default::default() + HashMap::default() } else { HookRegistry::default().table }; @@ -60,11 +68,7 @@ impl<'a> SP1ContextBuilder<'a> { }); let subproof_verifier = take(&mut self.subproof_verifier); let cycle_limit = take(&mut self.max_cycles); - SP1Context { - hook_registry, - subproof_verifier, - max_cycles: cycle_limit, - } + SP1Context { hook_registry, subproof_verifier, max_cycles: cycle_limit } } /// Add a runtime [Hook](super::Hook) into the context. @@ -112,15 +116,12 @@ impl<'a> SP1ContextBuilder<'a> { mod tests { use std::sync::Arc; - use crate::runtime::{DefaultSubproofVerifier, SP1Context}; + use crate::{subproof::DefaultSubproofVerifier, SP1Context}; #[test] fn defaults() { - let SP1Context { - hook_registry, - subproof_verifier, - max_cycles: cycle_limit, - } = SP1Context::builder().build(); + let SP1Context { hook_registry, subproof_verifier, max_cycles: cycle_limit } = + SP1Context::builder().build(); assert!(hook_registry.is_none()); assert!(subproof_verifier.is_none()); assert!(cycle_limit.is_none()); @@ -142,21 +143,14 @@ mod tests { #[test] fn without_default_hooks_with_custom_hook() { - let SP1Context { hook_registry, .. } = SP1Context::builder() - .without_default_hooks() - .hook(30, |_, _| vec![]) - .build(); - assert_eq!( - &hook_registry.unwrap().table.into_keys().collect::>(), - &[30] - ); + let SP1Context { hook_registry, .. } = + SP1Context::builder().without_default_hooks().hook(30, |_, _| vec![]).build(); + assert_eq!(&hook_registry.unwrap().table.into_keys().collect::>(), &[30]); } #[test] fn subproof_verifier() { - let SP1Context { - subproof_verifier, .. - } = SP1Context::builder() + let SP1Context { subproof_verifier, .. } = SP1Context::builder() .subproof_verifier(Arc::new(DefaultSubproofVerifier::new())) .build(); assert!(subproof_verifier.is_some()); diff --git a/core/src/disassembler/elf.rs b/crates/core/executor/src/disassembler/elf.rs similarity index 53% rename from core/src/disassembler/elf.rs rename to crates/core/executor/src/disassembler/elf.rs index 42454f5c72..d2ae639712 100644 --- a/core/src/disassembler/elf.rs +++ b/crates/core/executor/src/disassembler/elf.rs @@ -1,82 +1,81 @@ -use std::cmp::min; -use std::collections::BTreeMap; - -use elf::abi::{EM_RISCV, ET_EXEC, PF_X, PT_LOAD}; -use elf::endian::LittleEndian; -use elf::file::Class; -use elf::ElfBytes; - -/// The maximum size of the memory in bytes. -pub const MAXIMUM_MEMORY_SIZE: u32 = u32::MAX; - -/// The size of a word in bytes. -pub const WORD_SIZE: usize = 4; - -/// A RV32IM ELF file. +use std::{cmp::min, collections::BTreeMap}; + +use elf::{ + abi::{EM_RISCV, ET_EXEC, PF_X, PT_LOAD}, + endian::LittleEndian, + file::Class, + ElfBytes, +}; +use sp1_primitives::consts::{MAXIMUM_MEMORY_SIZE, WORD_SIZE}; + +/// RISC-V 32IM ELF (Executable and Linkable Format) File. +/// +/// This file represents a binary in the ELF format, specifically the RISC-V 32IM architecture +/// with the following extensions: +/// +/// - Base Integer Instruction Set (I) +/// - Integer Multiplication and Division (M) +/// +/// This format is commonly used in embedded systems and is supported by many compilers. #[derive(Debug, Clone)] -pub struct Elf { +pub(crate) struct Elf { /// The instructions of the program encoded as 32-bits. - pub instructions: Vec, - + pub(crate) instructions: Vec, /// The start address of the program. - pub pc_start: u32, - + pub(crate) pc_start: u32, /// The base address of the program. - pub pc_base: u32, - + pub(crate) pc_base: u32, /// The initial memory image, useful for global constants. - pub memory_image: BTreeMap, + pub(crate) memory_image: BTreeMap, } impl Elf { - /// Create a new ELF file. - pub const fn new( + /// Create a new [Elf]. + #[must_use] + pub(crate) const fn new( instructions: Vec, pc_start: u32, pc_base: u32, memory_image: BTreeMap, ) -> Self { - Self { - instructions, - pc_start, - pc_base, - memory_image, - } + Self { instructions, pc_start, pc_base, memory_image } } - /// Parse the ELF file into a vector of 32-bit encoded instructions and the first memory address. + /// Parse the ELF file into a vector of 32-bit encoded instructions and the first memory + /// address. + /// + /// # Errors /// - /// Reference: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format - pub fn decode(input: &[u8]) -> Self { + /// This function may return an error if the ELF is not valid. + /// + /// Reference: [Executable and Linkable Format](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) + pub(crate) fn decode(input: &[u8]) -> eyre::Result { let mut image: BTreeMap = BTreeMap::new(); + // Parse the ELF file assuming that it is little-endian.. - let elf = ElfBytes::::minimal_parse(input).expect("failed to parse elf"); + let elf = ElfBytes::::minimal_parse(input)?; // Some sanity checks to make sure that the ELF file is valid. if elf.ehdr.class != Class::ELF32 { - panic!("must be a 32-bit elf"); + eyre::bail!("must be a 32-bit elf"); } else if elf.ehdr.e_machine != EM_RISCV { - panic!("must be a riscv machine"); + eyre::bail!("must be a riscv machine"); } else if elf.ehdr.e_type != ET_EXEC { - panic!("must be executable"); + eyre::bail!("must be executable"); } // Get the entrypoint of the ELF file as an u32. - let entry: u32 = elf - .ehdr - .e_entry - .try_into() - .expect("e_entry was larger than 32 bits"); + let entry: u32 = elf.ehdr.e_entry.try_into()?; // Make sure the entrypoint is valid. if entry == MAXIMUM_MEMORY_SIZE || entry % WORD_SIZE as u32 != 0 { - panic!("invalid entrypoint"); + eyre::bail!("invalid entrypoint"); } // Get the segments of the ELF file. - let segments = elf.segments().expect("failed to get segments"); + let segments = elf.segments().ok_or_else(|| eyre::eyre!("failed to get segments"))?; if segments.len() > 256 { - panic!("too many program headers"); + eyre::bail!("too many program headers"); } let mut instructions: Vec = Vec::new(); @@ -85,30 +84,21 @@ impl Elf { // Only read segments that are executable instructions that are also PT_LOAD. for segment in segments.iter().filter(|x| x.p_type == PT_LOAD) { // Get the file size of the segment as an u32. - let file_size: u32 = segment - .p_filesz - .try_into() - .expect("filesize was larger than 32 bits"); + let file_size: u32 = segment.p_filesz.try_into()?; if file_size == MAXIMUM_MEMORY_SIZE { - panic!("invalid segment file_size"); + eyre::bail!("invalid segment file_size"); } // Get the memory size of the segment as an u32. - let mem_size: u32 = segment - .p_memsz - .try_into() - .expect("mem_size was larger than 32 bits"); + let mem_size: u32 = segment.p_memsz.try_into()?; if mem_size == MAXIMUM_MEMORY_SIZE { - panic!("Invalid segment mem_size"); + eyre::bail!("Invalid segment mem_size"); } // Get the virtual address of the segment as an u32. - let vaddr: u32 = segment - .p_vaddr - .try_into() - .expect("vaddr was larger than 32 bits"); + let vaddr: u32 = segment.p_vaddr.try_into()?; if vaddr % WORD_SIZE as u32 != 0 { - panic!("vaddr {vaddr:08x} is unaligned"); + eyre::bail!("vaddr {vaddr:08x} is unaligned"); } // If the virtual address is less than the first memory address, then update the first @@ -118,16 +108,15 @@ impl Elf { } // Get the offset to the segment. - let offset: u32 = segment - .p_offset - .try_into() - .expect("offset was larger than 32 bits"); + let offset: u32 = segment.p_offset.try_into()?; // Read the segment and decode each word as an instruction. for i in (0..mem_size).step_by(WORD_SIZE) { - let addr = vaddr.checked_add(i).expect("invalid segment vaddr"); + let addr = vaddr.checked_add(i).ok_or_else(|| eyre::eyre!("vaddr overflow"))?; if addr == MAXIMUM_MEMORY_SIZE { - panic!("address [0x{addr:08x}] exceeds maximum address for guest programs [0x{MAXIMUM_MEMORY_SIZE:08x}]"); + eyre::bail!( + "address [0x{addr:08x}] exceeds maximum address for guest programs [0x{MAXIMUM_MEMORY_SIZE:08x}]" + ); } // If we are reading past the end of the file, then break. @@ -141,8 +130,10 @@ impl Elf { let len = min(file_size - i, WORD_SIZE as u32); for j in 0..len { let offset = (offset + i + j) as usize; - let byte = input.get(offset).expect("invalid segment offset"); - word |= (*byte as u32) << (j * 8); + let byte = input + .get(offset) + .ok_or_else(|| eyre::eyre!("failed to read segment offset"))?; + word |= u32::from(*byte) << (j * 8); } image.insert(addr, word); if (segment.p_flags & PF_X) != 0 { @@ -151,6 +142,6 @@ impl Elf { } } - Elf::new(instructions, entry, base_address, image) + Ok(Elf::new(instructions, entry, base_address, image)) } } diff --git a/crates/core/executor/src/disassembler/mod.rs b/crates/core/executor/src/disassembler/mod.rs new file mode 100644 index 0000000000..3b7c68b77d --- /dev/null +++ b/crates/core/executor/src/disassembler/mod.rs @@ -0,0 +1,7 @@ +//! A disassembler for RISC-V ELFs. + +mod elf; +mod rrs; + +pub(crate) use elf::*; +pub(crate) use rrs::*; diff --git a/core/src/disassembler/instruction.rs b/crates/core/executor/src/disassembler/rrs.rs similarity index 58% rename from core/src/disassembler/instruction.rs rename to crates/core/executor/src/disassembler/rrs.rs index 9c0eb3e512..711dbe4e4a 100644 --- a/core/src/disassembler/instruction.rs +++ b/crates/core/executor/src/disassembler/rrs.rs @@ -1,13 +1,14 @@ -use rrs_lib::instruction_formats::{ - BType, IType, ITypeCSR, ITypeShamt, JType, RType, SType, UType, +use rrs_lib::{ + instruction_formats::{BType, IType, ITypeCSR, ITypeShamt, JType, RType, SType, UType}, + process_instruction, InstructionProcessor, }; -use rrs_lib::{process_instruction, InstructionProcessor}; -use crate::runtime::{Instruction, Opcode, Register}; +use crate::{Instruction, Opcode, Register}; impl Instruction { - /// Create a new instruction from an R-type instruction. - pub const fn from_r_type(opcode: Opcode, dec_insn: RType) -> Self { + /// Create a new [`Instruction`] from an R-type instruction. + #[must_use] + pub const fn from_r_type(opcode: Opcode, dec_insn: &RType) -> Self { Self::new( opcode, dec_insn.rd as u32, @@ -18,32 +19,21 @@ impl Instruction { ) } - /// Create a new instruction from an I-type instruction. - pub const fn from_i_type(opcode: Opcode, dec_insn: IType) -> Self { - Self::new( - opcode, - dec_insn.rd as u32, - dec_insn.rs1 as u32, - dec_insn.imm as u32, - false, - true, - ) + /// Create a new [`Instruction`] from an I-type instruction. + #[must_use] + pub const fn from_i_type(opcode: Opcode, dec_insn: &IType) -> Self { + Self::new(opcode, dec_insn.rd as u32, dec_insn.rs1 as u32, dec_insn.imm as u32, false, true) } - /// Create a new instruction from an I-type instruction with a shamt. - pub const fn from_i_type_shamt(opcode: Opcode, dec_insn: ITypeShamt) -> Self { - Self::new( - opcode, - dec_insn.rd as u32, - dec_insn.rs1 as u32, - dec_insn.shamt as u32, - false, - true, - ) + /// Create a new [`Instruction`] from an I-type instruction with a shamt. + #[must_use] + pub const fn from_i_type_shamt(opcode: Opcode, dec_insn: &ITypeShamt) -> Self { + Self::new(opcode, dec_insn.rd as u32, dec_insn.rs1 as u32, dec_insn.shamt, false, true) } - /// Create a new instruction from an S-type instruction. - pub const fn from_s_type(opcode: Opcode, dec_insn: SType) -> Self { + /// Create a new [`Instruction`] from an S-type instruction. + #[must_use] + pub const fn from_s_type(opcode: Opcode, dec_insn: &SType) -> Self { Self::new( opcode, dec_insn.rs2 as u32, @@ -54,8 +44,9 @@ impl Instruction { ) } - /// Create a new instruction from a B-type instruction. - pub const fn from_b_type(opcode: Opcode, dec_insn: BType) -> Self { + /// Create a new [`Instruction`] from a B-type instruction. + #[must_use] + pub const fn from_b_type(opcode: Opcode, dec_insn: &BType) -> Self { Self::new( opcode, dec_insn.rs1 as u32, @@ -66,25 +57,29 @@ impl Instruction { ) } - /// Create a new instruction that is not implemented. + /// Create a new [`Instruction`] that is not implemented. + #[must_use] pub const fn unimp() -> Self { Self::new(Opcode::UNIMP, 0, 0, 0, true, true) } - /// Returns if the instruction is an R-type instruction. - #[inline(always)] + /// Returns if the [`Instruction`] is an R-type instruction. + #[inline] + #[must_use] pub const fn is_r_type(&self) -> bool { !self.imm_c } - /// Returns whether the instruction is an I-type instruction. - #[inline(always)] + /// Returns whether the [`Instruction`] is an I-type instruction. + #[inline] + #[must_use] pub const fn is_i_type(&self) -> bool { self.imm_c } - /// Decode the instruction in the R-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the R-type format. + #[inline] + #[must_use] pub fn r_type(&self) -> (Register, Register, Register) { ( Register::from_u32(self.op_a), @@ -93,196 +88,182 @@ impl Instruction { ) } - /// Decode the instruction in the I-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the I-type format. + #[inline] + #[must_use] pub fn i_type(&self) -> (Register, Register, u32) { - ( - Register::from_u32(self.op_a), - Register::from_u32(self.op_b), - self.op_c, - ) + (Register::from_u32(self.op_a), Register::from_u32(self.op_b), self.op_c) } - /// Decode the instruction in the S-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the S-type format. + #[inline] + #[must_use] pub fn s_type(&self) -> (Register, Register, u32) { - ( - Register::from_u32(self.op_a), - Register::from_u32(self.op_b), - self.op_c, - ) + (Register::from_u32(self.op_a), Register::from_u32(self.op_b), self.op_c) } - /// Decode the instruction in the B-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the B-type format. + #[inline] + #[must_use] pub fn b_type(&self) -> (Register, Register, u32) { - ( - Register::from_u32(self.op_a), - Register::from_u32(self.op_b), - self.op_c, - ) + (Register::from_u32(self.op_a), Register::from_u32(self.op_b), self.op_c) } - /// Decode the instruction in the J-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the J-type format. + #[inline] + #[must_use] pub fn j_type(&self) -> (Register, u32) { (Register::from_u32(self.op_a), self.op_b) } - /// Decode the instruction in the U-type format. - #[inline(always)] + /// Decode the [`Instruction`] in the U-type format. + #[inline] + #[must_use] pub fn u_type(&self) -> (Register, u32) { (Register::from_u32(self.op_a), self.op_b) } } /// A transpiler that converts the 32-bit encoded instructions into instructions. -pub struct InstructionTranspiler; +pub(crate) struct InstructionTranspiler; impl InstructionProcessor for InstructionTranspiler { type InstructionResult = Instruction; fn process_add(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::ADD, dec_insn) + Instruction::from_r_type(Opcode::ADD, &dec_insn) } fn process_addi(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::ADD, dec_insn) + Instruction::from_i_type(Opcode::ADD, &dec_insn) } fn process_sub(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SUB, dec_insn) + Instruction::from_r_type(Opcode::SUB, &dec_insn) } fn process_xor(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::XOR, dec_insn) + Instruction::from_r_type(Opcode::XOR, &dec_insn) } fn process_xori(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::XOR, dec_insn) + Instruction::from_i_type(Opcode::XOR, &dec_insn) } fn process_or(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::OR, dec_insn) + Instruction::from_r_type(Opcode::OR, &dec_insn) } fn process_ori(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::OR, dec_insn) + Instruction::from_i_type(Opcode::OR, &dec_insn) } fn process_and(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::AND, dec_insn) + Instruction::from_r_type(Opcode::AND, &dec_insn) } fn process_andi(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::AND, dec_insn) + Instruction::from_i_type(Opcode::AND, &dec_insn) } fn process_sll(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SLL, dec_insn) + Instruction::from_r_type(Opcode::SLL, &dec_insn) } fn process_slli(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult { - Instruction::from_i_type_shamt(Opcode::SLL, dec_insn) + Instruction::from_i_type_shamt(Opcode::SLL, &dec_insn) } fn process_srl(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SRL, dec_insn) + Instruction::from_r_type(Opcode::SRL, &dec_insn) } fn process_srli(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult { - Instruction::from_i_type_shamt(Opcode::SRL, dec_insn) + Instruction::from_i_type_shamt(Opcode::SRL, &dec_insn) } fn process_sra(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SRA, dec_insn) + Instruction::from_r_type(Opcode::SRA, &dec_insn) } fn process_srai(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult { - Instruction::from_i_type_shamt(Opcode::SRA, dec_insn) + Instruction::from_i_type_shamt(Opcode::SRA, &dec_insn) } fn process_slt(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SLT, dec_insn) + Instruction::from_r_type(Opcode::SLT, &dec_insn) } fn process_slti(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::SLT, dec_insn) + Instruction::from_i_type(Opcode::SLT, &dec_insn) } fn process_sltu(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::SLTU, dec_insn) + Instruction::from_r_type(Opcode::SLTU, &dec_insn) } fn process_sltui(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::SLTU, dec_insn) + Instruction::from_i_type(Opcode::SLTU, &dec_insn) } fn process_lb(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::LB, dec_insn) + Instruction::from_i_type(Opcode::LB, &dec_insn) } fn process_lh(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::LH, dec_insn) + Instruction::from_i_type(Opcode::LH, &dec_insn) } fn process_lw(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::LW, dec_insn) + Instruction::from_i_type(Opcode::LW, &dec_insn) } fn process_lbu(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::LBU, dec_insn) + Instruction::from_i_type(Opcode::LBU, &dec_insn) } fn process_lhu(&mut self, dec_insn: IType) -> Self::InstructionResult { - Instruction::from_i_type(Opcode::LHU, dec_insn) + Instruction::from_i_type(Opcode::LHU, &dec_insn) } fn process_sb(&mut self, dec_insn: SType) -> Self::InstructionResult { - Instruction::from_s_type(Opcode::SB, dec_insn) + Instruction::from_s_type(Opcode::SB, &dec_insn) } fn process_sh(&mut self, dec_insn: SType) -> Self::InstructionResult { - Instruction::from_s_type(Opcode::SH, dec_insn) + Instruction::from_s_type(Opcode::SH, &dec_insn) } fn process_sw(&mut self, dec_insn: SType) -> Self::InstructionResult { - Instruction::from_s_type(Opcode::SW, dec_insn) + Instruction::from_s_type(Opcode::SW, &dec_insn) } fn process_beq(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BEQ, dec_insn) + Instruction::from_b_type(Opcode::BEQ, &dec_insn) } fn process_bne(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BNE, dec_insn) + Instruction::from_b_type(Opcode::BNE, &dec_insn) } fn process_blt(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BLT, dec_insn) + Instruction::from_b_type(Opcode::BLT, &dec_insn) } fn process_bge(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BGE, dec_insn) + Instruction::from_b_type(Opcode::BGE, &dec_insn) } fn process_bltu(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BLTU, dec_insn) + Instruction::from_b_type(Opcode::BLTU, &dec_insn) } fn process_bgeu(&mut self, dec_insn: BType) -> Self::InstructionResult { - Instruction::from_b_type(Opcode::BGEU, dec_insn) + Instruction::from_b_type(Opcode::BGEU, &dec_insn) } fn process_jal(&mut self, dec_insn: JType) -> Self::InstructionResult { - Instruction::new( - Opcode::JAL, - dec_insn.rd as u32, - dec_insn.imm as u32, - 0, - true, - true, - ) + Instruction::new(Opcode::JAL, dec_insn.rd as u32, dec_insn.imm as u32, 0, true, true) } fn process_jalr(&mut self, dec_insn: IType) -> Self::InstructionResult { @@ -296,17 +277,12 @@ impl InstructionProcessor for InstructionTranspiler { ) } - /// LUI instructions are converted to an SLL instruction with imm_b and imm_c turned on. - /// Additionally the op_c should be set to 12. fn process_lui(&mut self, dec_insn: UType) -> Self::InstructionResult { - Instruction::new( - Opcode::ADD, - dec_insn.rd as u32, - 0, - dec_insn.imm as u32, - true, - true, - ) + // LUI instructions are handled in a special way inside the zkVM. + // + // Notably, LUI instructions are converted to an SLL instruction with `imm_b` and `imm_c` + // turned on. Additionally the `op_c` should be set to 12. + Instruction::new(Opcode::ADD, dec_insn.rd as u32, 0, dec_insn.imm as u32, true, true) } /// AUIPC instructions have the third operand set to imm << 12. @@ -337,35 +313,35 @@ impl InstructionProcessor for InstructionTranspiler { } fn process_mul(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::MUL, dec_insn) + Instruction::from_r_type(Opcode::MUL, &dec_insn) } fn process_mulh(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::MULH, dec_insn) + Instruction::from_r_type(Opcode::MULH, &dec_insn) } fn process_mulhu(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::MULHU, dec_insn) + Instruction::from_r_type(Opcode::MULHU, &dec_insn) } fn process_mulhsu(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::MULHSU, dec_insn) + Instruction::from_r_type(Opcode::MULHSU, &dec_insn) } fn process_div(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::DIV, dec_insn) + Instruction::from_r_type(Opcode::DIV, &dec_insn) } fn process_divu(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::DIVU, dec_insn) + Instruction::from_r_type(Opcode::DIVU, &dec_insn) } fn process_rem(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::REM, dec_insn) + Instruction::from_r_type(Opcode::REM, &dec_insn) } fn process_remu(&mut self, dec_insn: RType) -> Self::InstructionResult { - Instruction::from_r_type(Opcode::REMU, dec_insn) + Instruction::from_r_type(Opcode::REMU, &dec_insn) } fn process_csrrc(&mut self, _: ITypeCSR) -> Self::InstructionResult { @@ -405,8 +381,13 @@ impl InstructionProcessor for InstructionTranspiler { } } -/// Transpile the instructions from the 32-bit encoded instructions. -pub fn transpile(instructions_u32: &[u32]) -> Vec { +/// Transpile the [`Instruction`]s from the 32-bit encoded instructions. +/// +/// # Panics +/// +/// This function will return an error if the [`Instruction`] cannot be processed. +#[must_use] +pub(crate) fn transpile(instructions_u32: &[u32]) -> Vec { let mut instructions = Vec::new(); let mut transpiler = InstructionTranspiler; for instruction_u32 in instructions_u32 { diff --git a/crates/core/executor/src/events/alu.rs b/crates/core/executor/src/events/alu.rs new file mode 100644 index 0000000000..67b30a6a19 --- /dev/null +++ b/crates/core/executor/src/events/alu.rs @@ -0,0 +1,49 @@ +use serde::{Deserialize, Serialize}; + +use crate::Opcode; + +use super::create_alu_lookups; + +/// Arithmetic Logic Unit (ALU) Event. +/// +/// This object encapsulated the information needed to prove an ALU operation. This includes its +/// shard, channel, opcode, operands, and other relevant information. +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct AluEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The opcode. + pub opcode: Opcode, + /// The first operand. + pub a: u32, + /// The second operand. + pub b: u32, + /// The third operand. + pub c: u32, + /// The result of the operation. + pub sub_lookups: [u128; 6], +} + +impl AluEvent { + /// Create a new [`AluEvent`]. + #[must_use] + pub fn new(shard: u32, channel: u8, clk: u32, opcode: Opcode, a: u32, b: u32, c: u32) -> Self { + Self { + lookup_id: 0, + shard, + channel, + clk, + opcode, + a, + b, + c, + sub_lookups: create_alu_lookups(), + } + } +} diff --git a/core/src/bytes/event.rs b/crates/core/executor/src/events/byte.rs similarity index 67% rename from core/src/bytes/event.rs rename to crates/core/executor/src/events/byte.rs index d96d8ea24d..2f2f0f043d 100644 --- a/core/src/bytes/event.rs +++ b/crates/core/executor/src/events/byte.rs @@ -1,58 +1,46 @@ -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use hashbrown::HashMap; use itertools::Itertools; -use p3_field::PrimeField32; +use p3_field::{Field, PrimeField32}; use p3_maybe_rayon::prelude::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, }; use serde::{Deserialize, Serialize}; -use super::ByteOpcode; +use crate::{ByteOpcode, Opcode}; -/// A byte lookup event. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +/// The number of different byte operations. +pub const NUM_BYTE_OPS: usize = 9; + +/// Byte Lookup Event. +/// +/// This object encapsulates the information needed to prove a byte lookup operation. This includes +/// the shard, channel, opcode, operands, and other relevant information. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct ByteLookupEvent { - /// The shard number, used for byte lookup table. + /// The shard number. pub shard: u32, - - // The channel multiplicity identifier. + /// The channel number. pub channel: u8, - - /// The opcode of the operation. + /// The opcode. pub opcode: ByteOpcode, - - /// The first output operand. + /// The first operand. pub a1: u16, - - /// The second output operand. + /// The second operand. pub a2: u8, - - /// The first input operand. + /// The third operand. pub b: u8, - - /// The second input operand. + /// The fourth operand. pub c: u8, } -impl Hash for ByteLookupEvent { - fn hash(&self, state: &mut H) { - let combined_limb_1 = self.shard as u64 - + ((self.channel as u64) << 32) - + ((self.opcode as u64) << 40) - + ((self.a1 as u64) << 48); - let combined_limb_2 = self.a2 as u64 + ((self.b as u64) << 8) + ((self.c as u64) << 16); - let combined = combined_limb_1 as u128 + ((combined_limb_2 as u128) << 64); - - combined.hash(state); - } -} - /// A type that can record byte lookup events. pub trait ByteRecord { - /// Adds a new `ByteLookupEvent` to the record. + /// Adds a new [`ByteLookupEvent`] to the record. fn add_byte_lookup_event(&mut self, blu_event: ByteLookupEvent); + /// Adds a list of sharded [`ByteLookupEvent`]s to the record. fn add_sharded_byte_lookup_events( &mut self, sharded_blu_events_vec: Vec<&HashMap>>, @@ -61,12 +49,12 @@ pub trait ByteRecord { /// Adds a list of `ByteLookupEvent`s to the record. #[inline] fn add_byte_lookup_events(&mut self, blu_events: Vec) { - for blu_event in blu_events.into_iter() { + for blu_event in blu_events { self.add_byte_lookup_event(blu_event); } } - /// Adds a `ByteLookupEvent` to verify `a` and `b are indeed bytes to the shard. + /// Adds a `ByteLookupEvent` to verify `a` and `b` are indeed bytes to the shard. fn add_u8_range_check(&mut self, shard: u32, channel: u8, a: u8, b: u8) { self.add_byte_lookup_event(ByteLookupEvent { shard, @@ -116,17 +104,13 @@ pub trait ByteRecord { self.add_u8_range_checks( shard, channel, - &field_values - .iter() - .map(|x| x.as_canonical_u32() as u8) - .collect::>(), + &field_values.iter().map(|x| x.as_canonical_u32() as u8).collect::>(), ); } /// Adds `ByteLookupEvent`s to verify that all the bytes in the input slice are indeed bytes. fn add_u16_range_checks(&mut self, shard: u32, channel: u8, ls: &[u16]) { - ls.iter() - .for_each(|x| self.add_u16_range_check(shard, channel, *x)); + ls.iter().for_each(|x| self.add_u16_range_check(shard, channel, *x)); } /// Adds a `ByteLookupEvent` to compute the bitwise OR of the two input values. @@ -145,17 +129,9 @@ pub trait ByteRecord { impl ByteLookupEvent { /// Creates a new `ByteLookupEvent`. - #[inline(always)] + #[must_use] pub fn new(shard: u32, channel: u8, opcode: ByteOpcode, a1: u16, a2: u8, b: u8, c: u8) -> Self { - Self { - shard, - channel, - opcode, - a1, - a2, - b, - c, - } + Self { shard, channel, opcode, a1, a2, b, c } } } @@ -199,12 +175,9 @@ pub(crate) fn add_sharded_byte_lookup_events( // per shard. let mut new_sharded_blu_map: HashMap>> = HashMap::new(); - for new_sharded_blu_events in new_events.into_iter() { - for (shard, new_blu_map) in new_sharded_blu_events.into_iter() { - new_sharded_blu_map - .entry(*shard) - .or_insert(Vec::new()) - .push(new_blu_map); + for new_sharded_blu_events in new_events { + for (shard, new_blu_map) in new_sharded_blu_events { + new_sharded_blu_map.entry(*shard).or_insert(Vec::new()).push(new_blu_map); } } @@ -214,7 +187,7 @@ pub(crate) fn add_sharded_byte_lookup_events( // Move ownership of self's per shard blu maps into a vec. This is so that we // can do parallel aggregation per shard. let mut self_blu_maps: Vec> = Vec::new(); - shards.iter().for_each(|shard| { + for shard in &shards { let blu = sharded_blu_events.remove(shard); match blu { @@ -225,23 +198,59 @@ pub(crate) fn add_sharded_byte_lookup_events( self_blu_maps.push(HashMap::new()); } } - }); + } // Increment self's byte lookup events multiplicity. - shards - .par_iter() - .zip_eq(self_blu_maps.par_iter_mut()) - .for_each(|(shard, self_blu_map)| { - let blu_map_vec = new_sharded_blu_map.get(shard).unwrap(); - for blu_map in blu_map_vec.iter() { - for (blu_event, count) in blu_map.iter() { - *self_blu_map.entry(*blu_event).or_insert(0) += count; - } + shards.par_iter().zip_eq(self_blu_maps.par_iter_mut()).for_each(|(shard, self_blu_map)| { + let blu_map_vec = new_sharded_blu_map.get(shard).unwrap(); + for blu_map in blu_map_vec.iter() { + for (blu_event, count) in blu_map.iter() { + *self_blu_map.entry(*blu_event).or_insert(0) += count; } - }); + } + }); // Move ownership of the blu maps back to self. for (shard, blu) in shards.into_iter().zip(self_blu_maps.into_iter()) { sharded_blu_events.insert(shard, blu); } } + +impl From for ByteOpcode { + /// Convert an opcode to a byte opcode. + fn from(value: Opcode) -> Self { + match value { + Opcode::AND => Self::AND, + Opcode::OR => Self::OR, + Opcode::XOR => Self::XOR, + Opcode::SLL => Self::SLL, + _ => panic!("Invalid opcode for ByteChip: {value:?}"), + } + } +} + +impl ByteOpcode { + /// Get all the byte opcodes. + #[must_use] + pub fn all() -> Vec { + let opcodes = vec![ + ByteOpcode::AND, + ByteOpcode::OR, + ByteOpcode::XOR, + ByteOpcode::SLL, + ByteOpcode::U8Range, + ByteOpcode::ShrCarry, + ByteOpcode::LTU, + ByteOpcode::MSB, + ByteOpcode::U16Range, + ]; + assert_eq!(opcodes.len(), NUM_BYTE_OPS); + opcodes + } + + /// Convert the opcode to a field element. + #[must_use] + pub fn as_field(self) -> F { + F::from_canonical_u8(self as u8) + } +} diff --git a/core/src/cpu/event.rs b/crates/core/executor/src/events/cpu.rs similarity index 50% rename from core/src/cpu/event.rs rename to crates/core/executor/src/events/cpu.rs index 06fb627726..31af950d4d 100644 --- a/core/src/cpu/event.rs +++ b/crates/core/executor/src/events/cpu.rs @@ -1,65 +1,63 @@ use serde::{Deserialize, Serialize}; -use crate::runtime::Instruction; -use crate::runtime::MemoryRecordEnum; +use crate::Instruction; -/// A standard format for describing CPU operations that need to be proven. +use super::memory::MemoryRecordEnum; + +/// CPU Event. +/// +/// This object encapsulates the information needed to prove a CPU operation. This includes its +/// shard, channel, opcode, operands, and other relevant information. #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct CpuEvent { - /// The current shard. + /// The shard number. pub shard: u32, - - /// The current channel. + /// The channel number. pub channel: u8, - - /// The current clock. + /// The clock cycle. pub clk: u32, - - /// The current program counter. + /// The program counter. pub pc: u32, - - /// The value of the next instruction's program counter. This value needs to be made public for - /// the last row of each shard. + /// The next program counter. pub next_pc: u32, - - /// The current instruction. + /// The instruction. pub instruction: Instruction, - /// The first operand. pub a: u32, - - /// The memory access record for the first operand. + /// The first operand memory record. pub a_record: Option, - /// The second operand. pub b: u32, - - /// The memory access record for the second operand. + /// The second operand memory record. pub b_record: Option, - /// The third operand. pub c: u32, - - /// The memory access record for the third operand. + /// The third operand memory record. pub c_record: Option, - - /// The memory value we potentially may access. + /// The memory value. pub memory: Option, - - /// The memory access record for the memory value. + /// The memory record. pub memory_record: Option, - - /// Exit code called with halt. + /// The exit code. pub exit_code: u32, - + /// The ALU lookup id. pub alu_lookup_id: u128, + /// The syscall lookup id. pub syscall_lookup_id: u128, + /// The memory add lookup id. pub memory_add_lookup_id: u128, + /// The memory sub lookup id. pub memory_sub_lookup_id: u128, + /// The branch gt lookup id. pub branch_gt_lookup_id: u128, + /// The branch lt lookup id. pub branch_lt_lookup_id: u128, + /// The branch add lookup id. pub branch_add_lookup_id: u128, + /// The jump jal lookup id. pub jump_jal_lookup_id: u128, + /// The jump jalr lookup id. pub jump_jalr_lookup_id: u128, + /// The auipc lookup id. pub auipc_lookup_id: u128, } diff --git a/crates/core/executor/src/events/memory.rs b/crates/core/executor/src/events/memory.rs new file mode 100644 index 0000000000..588fb18e99 --- /dev/null +++ b/crates/core/executor/src/events/memory.rs @@ -0,0 +1,179 @@ +use serde::{Deserialize, Serialize}; + +/// Memory Record. +/// +/// This object encapsulates the information needed to prove a memory access operation. This +/// includes the shard, timestamp, and value of the memory address. +#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] +pub struct MemoryRecord { + /// The shard number. + pub shard: u32, + /// The timestamp. + pub timestamp: u32, + /// The value. + pub value: u32, +} + +/// Memory Access Position. +/// +/// This enum represents the position of a memory access in a register. For example, if a memory +/// access is performed in the C register, it will have a position of C. +/// +/// Note: The register positions require that they be read and written in the following order: +/// C, B, A. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum MemoryAccessPosition { + /// Memory access position. + Memory = 0, + /// C register access position. + C = 1, + /// B register access position. + B = 2, + /// A register access position. + A = 3, +} + +/// Memory Read Record. +/// +/// This object encapsulates the information needed to prove a memory read operation. This +/// includes the value, shard, timestamp, and previous shard and timestamp. +#[allow(clippy::manual_non_exhaustive)] +#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] +pub struct MemoryReadRecord { + /// The value. + pub value: u32, + /// The shard number. + pub shard: u32, + /// The timestamp. + pub timestamp: u32, + /// The previous shard number. + pub prev_shard: u32, + /// The previous timestamp. + pub prev_timestamp: u32, +} + +/// Memory Write Record. +/// +/// This object encapsulates the information needed to prove a memory write operation. This +/// includes the value, shard, timestamp, previous value, previous shard, and previous timestamp. +#[allow(clippy::manual_non_exhaustive)] +#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] +pub struct MemoryWriteRecord { + /// The value. + pub value: u32, + /// The shard number. + pub shard: u32, + /// The timestamp. + pub timestamp: u32, + /// The previous value. + pub prev_value: u32, + /// The previous shard number. + pub prev_shard: u32, + /// The previous timestamp. + pub prev_timestamp: u32, +} + +/// Memory Record Enum. +/// +/// This enum represents the different types of memory records that can be stored in the memory +/// event such as reads and writes. +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub enum MemoryRecordEnum { + /// Read. + Read(MemoryReadRecord), + /// Write. + Write(MemoryWriteRecord), +} + +/// Memory Initialize/Finalize Event. +/// +/// This object encapsulates the information needed to prove a memory initialize or finalize +/// operation. This includes the address, value, shard, timestamp, and whether the memory is +/// initialized or finalized. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemoryInitializeFinalizeEvent { + /// The address. + pub addr: u32, + /// The value. + pub value: u32, + /// The shard number. + pub shard: u32, + /// The timestamp. + pub timestamp: u32, + /// The used flag. + pub used: u32, +} + +impl MemoryReadRecord { + /// Creates a new [``MemoryReadRecord``]. + #[must_use] + pub const fn new( + value: u32, + shard: u32, + timestamp: u32, + prev_shard: u32, + prev_timestamp: u32, + ) -> Self { + assert!(shard > prev_shard || ((shard == prev_shard) && (timestamp > prev_timestamp))); + Self { value, shard, timestamp, prev_shard, prev_timestamp } + } +} + +impl MemoryWriteRecord { + /// Creates a new [``MemoryWriteRecord``]. + #[must_use] + pub const fn new( + value: u32, + shard: u32, + timestamp: u32, + prev_value: u32, + prev_shard: u32, + prev_timestamp: u32, + ) -> Self { + assert!(shard > prev_shard || ((shard == prev_shard) && (timestamp > prev_timestamp)),); + Self { value, shard, timestamp, prev_value, prev_shard, prev_timestamp } + } +} + +impl MemoryRecordEnum { + /// Returns the value of the memory record. + #[must_use] + pub const fn value(&self) -> u32 { + match self { + MemoryRecordEnum::Read(record) => record.value, + MemoryRecordEnum::Write(record) => record.value, + } + } +} + +impl MemoryInitializeFinalizeEvent { + /// Creates a new [``MemoryInitializeFinalizeEvent``] for an initialization. + #[must_use] + pub const fn initialize(addr: u32, value: u32, used: bool) -> Self { + Self { addr, value, shard: 1, timestamp: 1, used: if used { 1 } else { 0 } } + } + + /// Creates a new [``MemoryInitializeFinalizeEvent``] for a finalization. + #[must_use] + pub const fn finalize_from_record(addr: u32, record: &MemoryRecord) -> Self { + Self { + addr, + value: record.value, + shard: record.shard, + timestamp: record.timestamp, + used: 1, + } + } +} + +impl From for MemoryRecordEnum { + fn from(read_record: MemoryReadRecord) -> Self { + MemoryRecordEnum::Read(read_record) + } +} + +impl From for MemoryRecordEnum { + fn from(write_record: MemoryWriteRecord) -> Self { + MemoryRecordEnum::Write(write_record) + } +} diff --git a/crates/core/executor/src/events/mod.rs b/crates/core/executor/src/events/mod.rs new file mode 100644 index 0000000000..9981e960af --- /dev/null +++ b/crates/core/executor/src/events/mod.rs @@ -0,0 +1,15 @@ +//! Type definitions for the events emitted by the [`crate::Executor`] during execution. + +mod alu; +mod byte; +mod cpu; +mod memory; +mod precompiles; +mod utils; + +pub use alu::*; +pub use byte::*; +pub use cpu::*; +pub use memory::*; +pub use precompiles::*; +pub use utils::*; diff --git a/core/src/syscall/precompiles/mod.rs b/crates/core/executor/src/events/precompiles/ec.rs similarity index 63% rename from core/src/syscall/precompiles/mod.rs rename to crates/core/executor/src/events/precompiles/ec.rs index aaf751fd2d..03efcb7749 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/crates/core/executor/src/events/precompiles/ec.rs @@ -1,45 +1,102 @@ -pub mod edwards; -pub mod keccak256; -pub mod sha256; -pub mod uint256; -pub mod weierstrass; -use crate::operations::field::params::{NumLimbs, NumWords}; -use crate::runtime::SyscallContext; -use crate::utils::ec::weierstrass::bls12_381::bls12381_decompress; -use crate::utils::ec::weierstrass::secp256k1::secp256k1_decompress; -use crate::utils::ec::CurveType; -use crate::utils::ec::{AffinePoint, EllipticCurve}; -use crate::utils::{bytes_to_words_le_vec, words_to_bytes_le_vec}; -use crate::{runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; +use serde::{Deserialize, Serialize}; + +use sp1_curves::{ + params::{NumLimbs, NumWords}, + weierstrass::{bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress}, + AffinePoint, CurveType, EllipticCurve, +}; +use sp1_primitives::consts::{bytes_to_words_le_vec, words_to_bytes_le_vec}; use typenum::Unsigned; -use core::fmt::Debug; -use serde::{Deserialize, Serialize}; +use crate::{ + events::memory::{MemoryReadRecord, MemoryWriteRecord}, + syscalls::SyscallContext, +}; -/// Elliptic curve add event. +/// Elliptic Curve Add Event. +/// +/// This event is emitted when an elliptic curve addition operation is performed. #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ECAddEvent { - pub lookup_id: u128, +pub struct EllipticCurveAddEvent { + pub(crate) lookup_id: u128, + /// The shard number. pub shard: u32, + /// The channel number. pub channel: u8, + /// The clock cycle. pub clk: u32, + /// The pointer to the first point. pub p_ptr: u32, + /// The first point as a list of words. pub p: Vec, + /// The pointer to the second point. pub q_ptr: u32, + /// The second point as a list of words. pub q: Vec, + /// The memory records for the first point. pub p_memory_records: Vec, + /// The memory records for the second point. pub q_memory_records: Vec, } +/// Elliptic Curve Double Event. +/// +/// This event is emitted when an elliptic curve doubling operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EllipticCurveDoubleEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the point. + pub p_ptr: u32, + /// The point as a list of words. + pub p: Vec, + /// The memory records for the point. + pub p_memory_records: Vec, +} + +/// Elliptic Curve Point Decompress Event. +/// +/// This event is emitted when an elliptic curve point decompression operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EllipticCurveDecompressEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the point. + pub ptr: u32, + /// The sign bit of the point. + pub sign_bit: bool, + /// The x coordinate as a list of bytes. + pub x_bytes: Vec, + /// The decompressed y coordinate as a list of bytes. + pub decompressed_y_bytes: Vec, + /// The memory records for the x coordinate. + pub x_memory_records: Vec, + /// The memory records for the y coordinate. + pub y_memory_records: Vec, +} + /// Create an elliptic curve add event. It takes two pointers to memory locations, reads the points /// from memory, adds them together, and writes the result back to the first memory location. -/// The generic parameter `N` is the number of u32 words in the point representation. For example, for -/// the secp256k1 curve, `N` would be 16 (64 bytes) because the x and y coordinates are 32 bytes each. +/// The generic parameter `N` is the number of u32 words in the point representation. For example, +/// for the secp256k1 curve, `N` would be 16 (64 bytes) because the x and y coordinates are 32 bytes +/// each. pub fn create_ec_add_event( rt: &mut SyscallContext, arg1: u32, arg2: u32, -) -> ECAddEvent { +) -> EllipticCurveAddEvent { let start_clk = rt.clk; let p_ptr = arg1; if p_ptr % 4 != 0 { @@ -67,7 +124,7 @@ pub fn create_ec_add_event( let p_memory_records = rt.mw_slice(p_ptr, &result_words); - ECAddEvent { + EllipticCurveAddEvent { lookup_id: rt.syscall_lookup_id, shard: rt.current_shard(), channel: rt.current_channel(), @@ -81,27 +138,15 @@ pub fn create_ec_add_event( } } -/// Elliptic curve double event. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ECDoubleEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub p_ptr: u32, - pub p: Vec, - pub p_memory_records: Vec, -} - -/// Create an elliptic curve double event. It takes a pointer to a memory location, reads the point -/// from memory, doubles it, and writes the result back to the memory location. The generic parameter -/// `N` is the number of u32 words in the point representation. For example, for the secp256k1 curve, `N` -/// would be 16 (64 bytes) because the x and y coordinates are 32 bytes each. +/// Create an elliptic curve double event. +/// +/// It takes a pointer to a memory location, reads the point from memory, doubles it, and writes the +/// result back to the memory location. pub fn create_ec_double_event( rt: &mut SyscallContext, arg1: u32, _: u32, -) -> ECDoubleEvent { +) -> EllipticCurveDoubleEvent { let start_clk = rt.clk; let p_ptr = arg1; if p_ptr % 4 != 0 { @@ -120,7 +165,7 @@ pub fn create_ec_double_event( let p_memory_records = rt.mw_slice(p_ptr, &result_words); - ECDoubleEvent { + EllipticCurveDoubleEvent { lookup_id: rt.syscall_lookup_id, shard: rt.current_shard(), channel: rt.current_channel(), @@ -131,26 +176,15 @@ pub fn create_ec_double_event( } } -/// Elliptic curve point decompress event. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ECDecompressEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub ptr: u32, - pub sign_bit: bool, - pub x_bytes: Vec, - pub decompressed_y_bytes: Vec, - pub x_memory_records: Vec, - pub y_memory_records: Vec, -} - +/// Create an elliptic curve decompress event. +/// +/// It takes a pointer to a memory location, reads the point from memory, decompresses it, and +/// writes the result back to the memory location. pub fn create_ec_decompress_event( rt: &mut SyscallContext, slice_ptr: u32, sign_bit: u32, -) -> ECDecompressEvent { +) -> EllipticCurveDecompressEvent { let start_clk = rt.clk; assert!(slice_ptr % 4 == 0, "slice_ptr must be 4-byte aligned"); assert!(sign_bit <= 1, "is_odd must be 0 or 1"); @@ -179,14 +213,14 @@ pub fn create_ec_decompress_event( let y_memory_records = rt.mw_slice(slice_ptr, &y_words); - ECDecompressEvent { + EllipticCurveDecompressEvent { lookup_id: rt.syscall_lookup_id, shard: rt.current_shard(), channel: rt.current_channel(), clk: start_clk, ptr: slice_ptr, sign_bit: sign_bit != 0, - x_bytes: x_bytes.to_vec(), + x_bytes: x_bytes.clone(), decompressed_y_bytes, x_memory_records, y_memory_records, diff --git a/crates/core/executor/src/events/precompiles/edwards.rs b/crates/core/executor/src/events/precompiles/edwards.rs new file mode 100644 index 0000000000..672602b2ef --- /dev/null +++ b/crates/core/executor/src/events/precompiles/edwards.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; +use sp1_curves::{edwards::WORDS_FIELD_ELEMENT, COMPRESSED_POINT_BYTES, NUM_BYTES_FIELD_ELEMENT}; + +use crate::events::memory::{MemoryReadRecord, MemoryWriteRecord}; + +/// Edwards Decompress Event. +/// +/// This event is emitted when an edwards decompression operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EdDecompressEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the point. + pub ptr: u32, + /// The sign bit of the point. + pub sign: bool, + /// The comprssed y coordinate as a list of bytes. + pub y_bytes: [u8; COMPRESSED_POINT_BYTES], + /// The decompressed x coordinate as a list of bytes. + pub decompressed_x_bytes: [u8; NUM_BYTES_FIELD_ELEMENT], + /// The memory records for the x coordinate. + pub x_memory_records: [MemoryWriteRecord; WORDS_FIELD_ELEMENT], + /// The memory records for the y coordinate. + pub y_memory_records: [MemoryReadRecord; WORDS_FIELD_ELEMENT], +} diff --git a/crates/core/executor/src/events/precompiles/fptower.rs b/crates/core/executor/src/events/precompiles/fptower.rs new file mode 100644 index 0000000000..bfe30431fe --- /dev/null +++ b/crates/core/executor/src/events/precompiles/fptower.rs @@ -0,0 +1,99 @@ +use serde::{Deserialize, Serialize}; + +use crate::events::{MemoryReadRecord, MemoryWriteRecord}; + +/// Airthmetic operation for emulating modular arithmetic. +#[derive(PartialEq, Copy, Clone, Debug, Serialize, Deserialize)] +pub enum FieldOperation { + /// Addition. + Add, + /// Multiplication. + Mul, + /// Subtraction. + Sub, + /// Division. + Div, +} + +/// Emulated Field Operation Events. +/// +/// This event is emitted when an emulated field operation is performed on the input operands. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FpOpEvent { + /// The lookup id. + pub lookup_id: usize, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the x operand. + pub x_ptr: u32, + /// The x operand. + pub x: Vec, + /// The pointer to the y operand. + pub y_ptr: u32, + /// The y operand. + pub y: Vec, + /// The operation to perform. + pub op: FieldOperation, + /// The memory records for the x operand. + pub x_memory_records: Vec, + /// The memory records for the y operand. + pub y_memory_records: Vec, +} + +/// Emulated Degree 2 Field Addition/Subtraction Events. +/// +/// This event is emitted when an emulated degree 2 field operation is performed on the input +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Fp2AddSubEvent { + /// The lookup id. + pub lookup_id: usize, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The operation to perform. + pub op: FieldOperation, + /// The pointer to the x operand. + pub x_ptr: u32, + /// The x operand. + pub x: Vec, + /// The pointer to the y operand. + pub y_ptr: u32, + /// The y operand. + pub y: Vec, + /// The memory records for the x operand. + pub x_memory_records: Vec, + /// The memory records for the y operand. + pub y_memory_records: Vec, +} + +/// Emulated Degree 2 Field Multiplication Events. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Fp2MulEvent { + /// The lookup id. + pub lookup_id: usize, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the x operand. + pub x_ptr: u32, + /// The x operand. + pub x: Vec, + /// The pointer to the y operand. + pub y_ptr: u32, + /// The y operand. + pub y: Vec, + /// The memory records for the x operand. + pub x_memory_records: Vec, + /// The memory records for the y operand. + pub y_memory_records: Vec, +} diff --git a/crates/core/executor/src/events/precompiles/keccak256_permute.rs b/crates/core/executor/src/events/precompiles/keccak256_permute.rs new file mode 100644 index 0000000000..e9934eb2d7 --- /dev/null +++ b/crates/core/executor/src/events/precompiles/keccak256_permute.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +use crate::events::memory::{MemoryReadRecord, MemoryWriteRecord}; + +pub(crate) const STATE_SIZE: usize = 25; + +/// Keccak-256 Permutation Event. +/// +/// This event is emitted when a keccak-256 permutation operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct KeccakPermuteEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pre-state as a list of u64 words. + pub pre_state: [u64; STATE_SIZE], + /// The post-state as a list of u64 words. + pub post_state: [u64; STATE_SIZE], + /// The memory records for the pre-state. + pub state_read_records: Vec, + /// The memory records for the post-state. + pub state_write_records: Vec, + /// The address of the state. + pub state_addr: u32, +} diff --git a/crates/core/executor/src/events/precompiles/mod.rs b/crates/core/executor/src/events/precompiles/mod.rs new file mode 100644 index 0000000000..ded0f62cd2 --- /dev/null +++ b/crates/core/executor/src/events/precompiles/mod.rs @@ -0,0 +1,15 @@ +mod ec; +mod edwards; +mod fptower; +mod keccak256_permute; +mod sha256_compress; +mod sha256_extend; +mod uint256; + +pub use ec::*; +pub use edwards::*; +pub use fptower::*; +pub use keccak256_permute::*; +pub use sha256_compress::*; +pub use sha256_extend::*; +pub use uint256::*; diff --git a/crates/core/executor/src/events/precompiles/sha256_compress.rs b/crates/core/executor/src/events/precompiles/sha256_compress.rs new file mode 100644 index 0000000000..421ed54e8d --- /dev/null +++ b/crates/core/executor/src/events/precompiles/sha256_compress.rs @@ -0,0 +1,32 @@ +use serde::{Deserialize, Serialize}; + +use crate::events::memory::{MemoryReadRecord, MemoryWriteRecord}; + +/// SHA-256 Compress Event. +/// +/// This event is emitted when a SHA-256 compress operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ShaCompressEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the word. + pub w_ptr: u32, + /// The word as a list of words. + pub h_ptr: u32, + /// The word as a list of words. + pub w: Vec, + /// The word as a list of words. + pub h: [u32; 8], + /// The memory records for the word. + pub h_read_records: [MemoryReadRecord; 8], + /// The memory records for the word. + pub w_i_read_records: Vec, + /// The memory records for the word. + pub h_write_records: [MemoryWriteRecord; 8], +} diff --git a/crates/core/executor/src/events/precompiles/sha256_extend.rs b/crates/core/executor/src/events/precompiles/sha256_extend.rs new file mode 100644 index 0000000000..64d7e4330c --- /dev/null +++ b/crates/core/executor/src/events/precompiles/sha256_extend.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +use crate::events::memory::{MemoryReadRecord, MemoryWriteRecord}; + +/// SHA-256 Extend Event. +/// +/// This event is emitted when a SHA-256 extend operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ShaExtendEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the word. + pub w_ptr: u32, + /// The memory reads of w[i-15]. + pub w_i_minus_15_reads: Vec, + /// The memory reads of w[i-2]. + pub w_i_minus_2_reads: Vec, + /// The memory reads of w[i-16]. + pub w_i_minus_16_reads: Vec, + /// The memory reads of w[i-7]. + pub w_i_minus_7_reads: Vec, + /// The memory writes of w[i]. + pub w_i_writes: Vec, +} diff --git a/crates/core/executor/src/events/precompiles/uint256.rs b/crates/core/executor/src/events/precompiles/uint256.rs new file mode 100644 index 0000000000..7c4cb136f4 --- /dev/null +++ b/crates/core/executor/src/events/precompiles/uint256.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; + +use crate::events::memory::{MemoryReadRecord, MemoryWriteRecord}; + +/// Uint256 Mul Event. +/// +/// This event is emitted when a uint256 mul operation is performed. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Uint256MulEvent { + /// The lookup identifer. + pub lookup_id: u128, + /// The shard number. + pub shard: u32, + /// The channel number. + pub channel: u8, + /// The clock cycle. + pub clk: u32, + /// The pointer to the x value. + pub x_ptr: u32, + /// The x value as a list of words. + pub x: Vec, + /// The pointer to the y value. + pub y_ptr: u32, + /// The y value as a list of words. + pub y: Vec, + /// The modulus as a list of words. + pub modulus: Vec, + /// The memory records for the x value. + pub x_memory_records: Vec, + /// The memory records for the y value. + pub y_memory_records: Vec, + /// The memory records for the modulus. + pub modulus_memory_records: Vec, +} diff --git a/crates/core/executor/src/events/utils.rs b/crates/core/executor/src/events/utils.rs new file mode 100644 index 0000000000..7ef304ae44 --- /dev/null +++ b/crates/core/executor/src/events/utils.rs @@ -0,0 +1,50 @@ +use std::{ + fmt::Display, + iter::{Map, Peekable}, +}; + +use rand::{thread_rng, Rng}; + +/// Creates a new ALU lookup id. +#[must_use] +pub fn create_alu_lookup_id() -> u128 { + let mut rng = thread_rng(); + rng.gen() +} + +/// Creates a new ALU lookup ids. +#[must_use] +pub fn create_alu_lookups() -> [u128; 6] { + let mut rng = thread_rng(); + [rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()] +} + +/// Returns sorted and formatted rows of a table of counts (e.g. `opcode_counts`). +/// +/// The table is sorted first by count (descending) and then by label (ascending). +/// The first column consists of the counts, is right-justified, and is padded precisely +/// enough to fit all the numbers. The second column consists of the labels (e.g. `OpCode`s). +/// The columns are separated by a single space character. +#[allow(clippy::type_complexity)] +pub fn sorted_table_lines<'a, K, V>( + table: impl IntoIterator + 'a, +) -> Map< + Peekable, impl FnMut((K, V)) -> (String, String)>>, + impl FnMut((String, String)) -> String, +> +where + K: Ord + Display + 'a, + V: Ord + Display + 'a, +{ + let mut entries = table.into_iter().collect::>(); + // Sort table by count (descending), then the name order (ascending). + entries.sort_unstable_by(|a, b| a.1.cmp(&b.1).reverse().then_with(|| a.0.cmp(&b.0))); + // Convert counts to `String`s to prepare them for printing and to measure their width. + let mut table_with_string_counts = entries + .into_iter() + .map(|(label, ct)| (label.to_string().to_lowercase(), ct.to_string())) + .peekable(); + // Calculate width for padding the counts. + let width = table_with_string_counts.peek().map(|(_, b)| b.len()).unwrap_or_default(); + table_with_string_counts.map(move |(label, count)| format!("{count:>width$} {label}")) +} diff --git a/core/src/runtime/mod.rs b/crates/core/executor/src/executor.rs similarity index 77% rename from core/src/runtime/mod.rs rename to crates/core/executor/src/executor.rs index 920f5012bd..539034276e 100644 --- a/core/src/runtime/mod.rs +++ b/crates/core/executor/src/executor.rs @@ -1,58 +1,35 @@ -mod context; -mod hooks; -mod instruction; -mod io; -mod memory; -mod opcode; -mod program; -mod record; -mod register; -mod report; -mod state; -mod syscall; -#[macro_use] -mod utils; -mod subproof; - -pub use context::*; -pub use hooks::*; -pub use instruction::*; -pub use memory::*; -pub use opcode::*; -pub use program::*; -pub use record::*; -pub use register::*; -pub use report::*; -pub use state::*; -pub use subproof::*; -pub use syscall::*; -pub use utils::*; - -use std::collections::hash_map::Entry; -use std::collections::HashMap; -use std::fs::File; -use std::io::BufWriter; -use std::io::Write; -use std::sync::Arc; - +use std::{ + fs::File, + io::{BufWriter, Write}, + sync::Arc, +}; + +use hashbrown::{hash_map::Entry, HashMap}; +use nohash_hasher::BuildNoHashHasher; use serde::{Deserialize, Serialize}; +use sp1_stark::SP1CoreOpts; use thiserror::Error; -use crate::alu::create_alu_lookup_id; -use crate::alu::create_alu_lookups; -use crate::bytes::NUM_BYTE_LOOKUP_CHANNELS; -use crate::memory::MemoryInitializeFinalizeEvent; -use crate::utils::SP1CoreOpts; -use crate::{alu::AluEvent, cpu::CpuEvent}; - -/// An implementation of a runtime for the SP1 RISC-V zkVM. +use crate::{ + context::SP1Context, + events::{ + create_alu_lookup_id, create_alu_lookups, AluEvent, CpuEvent, MemoryAccessPosition, + MemoryInitializeFinalizeEvent, MemoryReadRecord, MemoryRecord, MemoryWriteRecord, + }, + hook::{HookEnv, HookRegistry}, + record::{ExecutionRecord, MemoryAccessRecord}, + report::ExecutionReport, + state::{ExecutionState, ForkState}, + subproof::{DefaultSubproofVerifier, SubproofVerifier}, + syscalls::{default_syscall_map, Syscall, SyscallCode, SyscallContext}, + Instruction, Opcode, Program, Register, +}; + +/// An executor for the SP1 RISC-V zkVM. /// -/// The runtime is responsible for executing a user program and tracing important events which occur -/// during execution (i.e., memory reads, alu operations, etc). -/// -/// For more information on the RV32IM instruction set, see the following: -/// https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf -pub struct Runtime<'a> { +/// The exeuctor is responsible for executing a user program and tracing important events which +/// occur during execution (i.e., memory reads, alu operations, etc). +pub struct Executor<'a> { /// The program. pub program: Arc, @@ -71,6 +48,7 @@ pub struct Runtime<'a> { /// The maximum size of each shard. pub shard_size: u32, + /// The maximimum number of shards to execute at once. pub shard_batch_size: u32, /// A counter for the number of cycles that have been executed in certain functions. @@ -84,12 +62,13 @@ pub struct Runtime<'a> { /// Whether the runtime is in constrained mode or not. /// - /// In unconstrained mode, any events, clock, register, or memory changes are reset after leaving - /// the unconstrained block. The only thing preserved is writes to the input stream. + /// In unconstrained mode, any events, clock, register, or memory changes are reset after + /// leaving the unconstrained block. The only thing preserved is writes to the input + /// stream. pub unconstrained: bool, /// The state of the runtime when in unconstrained mode. - pub(crate) unconstrained_state: ForkState, + pub unconstrained_state: ForkState, /// The mapping between syscall codes and their implementations. pub syscall_map: HashMap>, @@ -97,8 +76,8 @@ pub struct Runtime<'a> { /// The maximum number of cycles for a syscall. pub max_syscall_cycles: u32, - /// Whether to emit events during execution. - pub emit_events: bool, + /// The mode the executor is running in. + pub executor_mode: ExecutorMode, /// Report of the program execution. pub report: ExecutionReport, @@ -112,47 +91,88 @@ pub struct Runtime<'a> { /// Registry of hooks, to be invoked by writing to certain file descriptors. pub hook_registry: HookRegistry<'a>, - // The options for the runtime. + /// The options for the runtime. pub opts: SP1CoreOpts, /// The maximum number of cpu cycles to use for execution. pub max_cycles: Option, + + /// Memory addresses that were touched in this batch of shards. Used to minimize the size of + /// checkpoints. + pub memory_checkpoint: HashMap, BuildNoHashHasher>, } +/// The different modes the executor can run in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExecutorMode { + /// Run the execution with no tracing or checkpointing. + Simple, + /// Run the execution with checkpoints for memory. + Checkpoint, + /// Run the execution with full tracing of events. + Trace, +} + +/// Errors that the [``Executor``] can throw. #[derive(Error, Debug, Serialize, Deserialize)] pub enum ExecutionError { + /// The execution failed with a non-zero exit code. #[error("execution failed with exit code {0}")] HaltWithNonZeroExitCode(u32), + + /// The execution failed with an invalid memory access. #[error("invalid memory access for opcode {0} and address {1}")] InvalidMemoryAccess(Opcode, u32), + + /// The execution failed with an unimplemented syscall. #[error("unimplemented syscall {0}")] UnsupportedSyscall(u32), + + /// The execution failed with a breakpoint. #[error("breakpoint encountered")] Breakpoint(), + + /// The execution failed with an exceeded cycle limit. #[error("exceeded cycle limit of {0}")] ExceededCycleLimit(u64), + + /// The execution failed because the syscall was called in unconstrained mode. + #[error("syscall called in unconstrained mode")] + InvalidSyscallUsage(u64), + + /// The execution failed with an unimplemented feature. #[error("got unimplemented as opcode")] Unimplemented(), } -impl<'a> Runtime<'a> { - // Create a new runtime from a program and options. +macro_rules! assert_valid_memory_access { + ($addr:expr, $position:expr) => { + #[cfg(not(debug_assertions))] + {} + }; +} + +impl<'a> Executor<'a> { + /// Create a new [``Executor``] from a program and options. + #[must_use] pub fn new(program: Program, opts: SP1CoreOpts) -> Self { - Self::with_context(program, opts, Default::default()) + Self::with_context(program, opts, SP1Context::default()) } /// Create a new runtime from a program, options, and a context. + /// + /// # Panics + /// + /// This function may panic if it fails to create the trace file if `TRACE_FILE` is set. + #[must_use] pub fn with_context(program: Program, opts: SP1CoreOpts, context: SP1Context<'a>) -> Self { // Create a shared reference to the program. let program = Arc::new(program); // Create a default record with the program. - let record = ExecutionRecord { - program: program.clone(), - ..Default::default() - }; + let record = ExecutionRecord { program: program.clone(), ..Default::default() }; - // If TRACE_FILE is set, initialize the trace buffer. + // If `TRACE_FILE`` is set, initialize the trace buffer. let trace_buf = if let Ok(trace_file) = std::env::var("TRACE_FILE") { let file = File::create(trace_file).unwrap(); Some(BufWriter::new(file)) @@ -162,15 +182,11 @@ impl<'a> Runtime<'a> { // Determine the maximum number of cycles for any syscall. let syscall_map = default_syscall_map(); - let max_syscall_cycles = syscall_map - .values() - .map(|syscall| syscall.num_extra_cycles()) - .max() - .unwrap_or(0); - - let subproof_verifier = context - .subproof_verifier - .unwrap_or_else(|| Arc::new(DefaultSubproofVerifier::new())); + let max_syscall_cycles = + syscall_map.values().map(|syscall| syscall.num_extra_cycles()).max().unwrap_or(0); + + let subproof_verifier = + context.subproof_verifier.unwrap_or_else(|| Arc::new(DefaultSubproofVerifier::new())); let hook_registry = context.hook_registry.unwrap_or_default(); Self { @@ -187,7 +203,7 @@ impl<'a> Runtime<'a> { unconstrained: false, unconstrained_state: ForkState::default(), syscall_map, - emit_events: true, + executor_mode: ExecutorMode::Trace, max_syscall_cycles, report: ExecutionReport::default(), print_report: false, @@ -195,36 +211,59 @@ impl<'a> Runtime<'a> { hook_registry, opts, max_cycles: context.max_cycles, + memory_checkpoint: HashMap::default(), } } - /// Invokes the hook corresponding to the given file descriptor `fd` with the data `buf`, - /// returning the resulting data. - pub fn hook(&self, fd: u32, buf: &[u8]) -> Vec> { - self.hook_registry - .get(&fd) - .unwrap() - .invoke_hook(self.hook_env(), buf) + /// Invokes a hook with the given file descriptor `fd` with the data `buf`. + /// + /// # Errors + /// + /// If the file descriptor is not found in the [``HookRegistry``], this function will return an + /// error. + pub fn hook(&self, fd: u32, buf: &[u8]) -> eyre::Result>> { + Ok(self + .hook_registry + .get(fd) + .ok_or(eyre::eyre!("no hook found for file descriptor {}", fd))? + .invoke_hook(self.hook_env(), buf)) } /// Prepare a `HookEnv` for use by hooks. + #[must_use] pub fn hook_env<'b>(&'b self) -> HookEnv<'b, 'a> { HookEnv { runtime: self } } /// Recover runtime state from a program and existing execution state. + #[must_use] pub fn recover(program: Program, state: ExecutionState, opts: SP1CoreOpts) -> Self { - let mut runtime = Self::new(program.clone(), opts); + let mut runtime = Self::new(program, opts); runtime.state = state; runtime } /// Get the current values of the registers. - pub fn registers(&self) -> [u32; 32] { + #[allow(clippy::single_match_else)] + #[must_use] + pub fn registers(&mut self) -> [u32; 32] { let mut registers = [0; 32]; for i in 0..32 { let addr = Register::from_u32(i as u32) as u32; - registers[i] = match self.state.memory.get(&addr) { + let record = self.state.memory.get(&addr); + + if self.executor_mode != ExecutorMode::Simple { + match record { + Some(record) => { + self.memory_checkpoint.entry(addr).or_insert_with(|| Some(*record)); + } + None => { + self.memory_checkpoint.entry(addr).or_insert(None); + } + } + } + + registers[i] = match record { Some(record) => record.value, None => 0, }; @@ -233,39 +272,73 @@ impl<'a> Runtime<'a> { } /// Get the current value of a register. - pub fn register(&self, register: Register) -> u32 { + #[must_use] + pub fn register(&mut self, register: Register) -> u32 { let addr = register as u32; - match self.state.memory.get(&addr) { + let record = self.state.memory.get(&addr); + + if self.executor_mode != ExecutorMode::Simple { + match record { + Some(record) => { + self.memory_checkpoint.entry(addr).or_insert_with(|| Some(*record)); + } + None => { + self.memory_checkpoint.entry(addr).or_insert(None); + } + } + } + + match record { Some(record) => record.value, None => 0, } } /// Get the current value of a word. - pub fn word(&self, addr: u32) -> u32 { - match self.state.memory.get(&addr) { + #[must_use] + pub fn word(&mut self, addr: u32) -> u32 { + #[allow(clippy::single_match_else)] + let record = self.state.memory.get(&addr); + + if self.executor_mode != ExecutorMode::Simple { + match record { + Some(record) => { + self.memory_checkpoint.entry(addr).or_insert_with(|| Some(*record)); + } + None => { + self.memory_checkpoint.entry(addr).or_insert(None); + } + } + } + + match record { Some(record) => record.value, None => 0, } } /// Get the current value of a byte. - pub fn byte(&self, addr: u32) -> u8 { + #[must_use] + pub fn byte(&mut self, addr: u32) -> u8 { let word = self.word(addr - addr % 4); (word >> ((addr % 4) * 8)) as u8 } /// Get the current timestamp for a given memory access position. + #[must_use] pub const fn timestamp(&self, position: &MemoryAccessPosition) -> u32 { self.state.clk + *position as u32 } /// Get the current shard. + #[must_use] #[inline] pub fn shard(&self) -> u32 { self.state.current_shard } + /// Get the current channel. + #[must_use] #[inline] pub fn channel(&self) -> u8 { self.state.channel @@ -275,6 +348,17 @@ impl<'a> Runtime<'a> { pub fn mr(&mut self, addr: u32, shard: u32, timestamp: u32) -> MemoryReadRecord { // Get the memory record entry. let entry = self.state.memory.entry(addr); + if self.executor_mode != ExecutorMode::Simple { + match entry { + Entry::Occupied(ref entry) => { + let record = entry.get(); + self.memory_checkpoint.entry(addr).or_insert_with(|| Some(*record)); + } + Entry::Vacant(_) => { + self.memory_checkpoint.entry(addr).or_insert(None); + } + } + } // If we're in unconstrained mode, we don't want to modify state, so we'll save the // original state if it's the first time modifying it. @@ -283,10 +367,7 @@ impl<'a> Runtime<'a> { Entry::Occupied(ref entry) => Some(entry.get()), Entry::Vacant(_) => None, }; - self.unconstrained_state - .memory_diff - .entry(addr) - .or_insert(record.copied()); + self.unconstrained_state.memory_diff.entry(addr).or_insert(record.copied()); } // If it's the first time accessing this address, initialize previous values. @@ -295,11 +376,7 @@ impl<'a> Runtime<'a> { Entry::Vacant(entry) => { // If addr has a specific value to be initialized with, use that, otherwise 0. let value = self.state.uninitialized_memory.get(&addr).unwrap_or(&0); - entry.insert(MemoryRecord { - value: *value, - shard: 0, - timestamp: 0, - }) + entry.insert(MemoryRecord { value: *value, shard: 0, timestamp: 0 }) } }; let value = record.value; @@ -316,6 +393,17 @@ impl<'a> Runtime<'a> { pub fn mw(&mut self, addr: u32, value: u32, shard: u32, timestamp: u32) -> MemoryWriteRecord { // Get the memory record entry. let entry = self.state.memory.entry(addr); + if self.executor_mode != ExecutorMode::Simple { + match entry { + Entry::Occupied(ref entry) => { + let record = entry.get(); + self.memory_checkpoint.entry(addr).or_insert_with(|| Some(*record)); + } + Entry::Vacant(_) => { + self.memory_checkpoint.entry(addr).or_insert(None); + } + } + } // If we're in unconstrained mode, we don't want to modify state, so we'll save the // original state if it's the first time modifying it. @@ -324,10 +412,7 @@ impl<'a> Runtime<'a> { Entry::Occupied(ref entry) => Some(entry.get()), Entry::Vacant(_) => None, }; - self.unconstrained_state - .memory_diff - .entry(addr) - .or_insert(record.copied()); + self.unconstrained_state.memory_diff.entry(addr).or_insert(record.copied()); } // If it's the first time accessing this address, initialize previous values. @@ -337,11 +422,7 @@ impl<'a> Runtime<'a> { // If addr has a specific value to be initialized with, use that, otherwise 0. let value = self.state.uninitialized_memory.get(&addr).unwrap_or(&0); - entry.insert(MemoryRecord { - value: *value, - shard: 0, - timestamp: 0, - }) + entry.insert(MemoryRecord { value: *value, shard: 0, timestamp: 0 }) } }; let prev_value = record.value; @@ -352,14 +433,7 @@ impl<'a> Runtime<'a> { record.timestamp = timestamp; // Construct the memory write record. - MemoryWriteRecord::new( - value, - shard, - timestamp, - prev_value, - prev_shard, - prev_timestamp, - ) + MemoryWriteRecord::new(value, shard, timestamp, prev_value, prev_shard, prev_timestamp) } /// Read from memory, assuming that all addresses are aligned. @@ -371,7 +445,7 @@ impl<'a> Runtime<'a> { let record = self.mr(addr, self.shard(), self.timestamp(&position)); // If we're not in unconstrained mode, record the access for the current cycle. - if !self.unconstrained && self.emit_events { + if !self.unconstrained && self.executor_mode == ExecutorMode::Trace { match position { MemoryAccessPosition::A => self.memory_accesses.a = Some(record.into()), MemoryAccessPosition::B => self.memory_accesses.b = Some(record.into()), @@ -383,6 +457,11 @@ impl<'a> Runtime<'a> { } /// Write to memory. + /// + /// # Panics + /// + /// This function will panic if the address is not aligned or if the memory accesses are already + /// initialized. pub fn mw_cpu(&mut self, addr: u32, value: u32, position: MemoryAccessPosition) { // Assert that the address is aligned. assert_valid_memory_access!(addr, position); @@ -391,7 +470,7 @@ impl<'a> Runtime<'a> { let record = self.mw(addr, value, self.shard(), self.timestamp(&position)); // If we're not in unconstrained mode, record the access for the current cycle. - if !self.unconstrained { + if !self.unconstrained && self.executor_mode == ExecutorMode::Trace { match position { MemoryAccessPosition::A => { assert!(self.memory_accesses.a.is_none()); @@ -426,7 +505,7 @@ impl<'a> Runtime<'a> { if register == Register::X0 { self.mw_cpu(register as u32, 0, MemoryAccessPosition::A); } else { - self.mw_cpu(register as u32, value, MemoryAccessPosition::A) + self.mw_cpu(register as u32, value, MemoryAccessPosition::A); } } @@ -523,7 +602,7 @@ impl<'a> Runtime<'a> { } /// Fetch the destination register and input operand values for an ALU instruction. - fn alu_rr(&mut self, instruction: Instruction) -> (Register, u32, u32) { + fn alu_rr(&mut self, instruction: &Instruction) -> (Register, u32, u32) { if !instruction.imm_c { let (rd, rs1, rs2) = instruction.r_type(); let c = self.rr(rs2, MemoryAccessPosition::C); @@ -535,11 +614,8 @@ impl<'a> Runtime<'a> { (rd, b, c) } else { assert!(instruction.imm_b && instruction.imm_c); - let (rd, b, c) = ( - Register::from_u32(instruction.op_a), - instruction.op_b, - instruction.op_c, - ); + let (rd, b, c) = + (Register::from_u32(instruction.op_a), instruction.op_b, instruction.op_c); (rd, b, c) } } @@ -547,7 +623,7 @@ impl<'a> Runtime<'a> { /// Set the destination register with the result and emit an ALU event. fn alu_rw( &mut self, - instruction: Instruction, + instruction: &Instruction, rd: Register, a: u32, b: u32, @@ -555,13 +631,13 @@ impl<'a> Runtime<'a> { lookup_id: u128, ) { self.rw(rd, a); - if self.emit_events { + if self.executor_mode == ExecutorMode::Trace { self.emit_alu(self.state.clk, instruction.opcode, a, b, c, lookup_id); } } /// Fetch the input operand values for a load instruction. - fn load_rr(&mut self, instruction: Instruction) -> (Register, u32, u32, u32, u32) { + fn load_rr(&mut self, instruction: &Instruction) -> (Register, u32, u32, u32, u32) { let (rd, rs1, imm) = instruction.i_type(); let (b, c) = (self.rr(rs1, MemoryAccessPosition::B), imm); let addr = b.wrapping_add(c); @@ -570,7 +646,7 @@ impl<'a> Runtime<'a> { } /// Fetch the input operand values for a store instruction. - fn store_rr(&mut self, instruction: Instruction) -> (u32, u32, u32, u32, u32) { + fn store_rr(&mut self, instruction: &Instruction) -> (u32, u32, u32, u32, u32) { let (rs1, rs2, imm) = instruction.s_type(); let c = imm; let b = self.rr(rs2, MemoryAccessPosition::B); @@ -581,7 +657,7 @@ impl<'a> Runtime<'a> { } /// Fetch the input operand values for a branch instruction. - fn branch_rr(&mut self, instruction: Instruction) -> (u32, u32, u32) { + fn branch_rr(&mut self, instruction: &Instruction) -> (u32, u32, u32) { let (rs1, rs2, imm) = instruction.b_type(); let c = imm; let b = self.rr(rs2, MemoryAccessPosition::B); @@ -596,7 +672,8 @@ impl<'a> Runtime<'a> { } /// Execute the given instruction over the current state of the runtime. - fn execute_instruction(&mut self, instruction: Instruction) -> Result<(), ExecutionError> { + #[allow(clippy::too_many_lines)] + fn execute_instruction(&mut self, instruction: &Instruction) -> Result<(), ExecutionError> { let mut pc = self.state.pc; let mut clk = self.state.clk; let mut exit_code = 0u32; @@ -607,10 +684,14 @@ impl<'a> Runtime<'a> { let (a, b, c): (u32, u32, u32); let (addr, memory_read_value): (u32, u32); let mut memory_store_value: Option = None; - self.memory_accesses = MemoryAccessRecord::default(); - let lookup_id = create_alu_lookup_id(); - let syscall_lookup_id = create_alu_lookup_id(); + if self.executor_mode != ExecutorMode::Simple { + self.memory_accesses = MemoryAccessRecord::default(); + } + let lookup_id = + if self.executor_mode == ExecutorMode::Simple { 0 } else { create_alu_lookup_id() }; + let syscall_lookup_id = + if self.executor_mode == ExecutorMode::Simple { 0 } else { create_alu_lookup_id() }; if self.print_report && !self.unconstrained { self.report @@ -687,8 +768,8 @@ impl<'a> Runtime<'a> { return Err(ExecutionError::InvalidMemoryAccess(Opcode::LH, addr)); } let value = match (addr >> 1) % 2 { - 0 => memory_read_value & 0x0000FFFF, - 1 => (memory_read_value & 0xFFFF0000) >> 16, + 0 => memory_read_value & 0x0000_FFFF, + 1 => (memory_read_value & 0xFFFF_0000) >> 16, _ => unreachable!(), }; a = ((value as i16) as i32) as u32; @@ -717,8 +798,8 @@ impl<'a> Runtime<'a> { return Err(ExecutionError::InvalidMemoryAccess(Opcode::LHU, addr)); } let value = match (addr >> 1) % 2 { - 0 => memory_read_value & 0x0000FFFF, - 1 => (memory_read_value & 0xFFFF0000) >> 16, + 0 => memory_read_value & 0x0000_FFFF, + 1 => (memory_read_value & 0xFFFF_0000) >> 16, _ => unreachable!(), }; a = (value as u16) as u32; @@ -730,10 +811,10 @@ impl<'a> Runtime<'a> { Opcode::SB => { (a, b, c, addr, memory_read_value) = self.store_rr(instruction); let value = match addr % 4 { - 0 => (a & 0x000000FF) + (memory_read_value & 0xFFFFFF00), - 1 => ((a & 0x000000FF) << 8) + (memory_read_value & 0xFFFF00FF), - 2 => ((a & 0x000000FF) << 16) + (memory_read_value & 0xFF00FFFF), - 3 => ((a & 0x000000FF) << 24) + (memory_read_value & 0x00FFFFFF), + 0 => (a & 0x0000_00FF) + (memory_read_value & 0xFFFF_FF00), + 1 => ((a & 0x0000_00FF) << 8) + (memory_read_value & 0xFFFF_00FF), + 2 => ((a & 0x0000_00FF) << 16) + (memory_read_value & 0xFF00_FFFF), + 3 => ((a & 0x0000_00FF) << 24) + (memory_read_value & 0x00FF_FFFF), _ => unreachable!(), }; memory_store_value = Some(value); @@ -745,8 +826,8 @@ impl<'a> Runtime<'a> { return Err(ExecutionError::InvalidMemoryAccess(Opcode::SH, addr)); } let value = match (addr >> 1) % 2 { - 0 => (a & 0x0000FFFF) + (memory_read_value & 0xFFFF0000), - 1 => ((a & 0x0000FFFF) << 16) + (memory_read_value & 0x0000FFFF), + 0 => (a & 0x0000_FFFF) + (memory_read_value & 0xFFFF_0000), + 1 => ((a & 0x0000_FFFF) << 16) + (memory_read_value & 0x0000_FFFF), _ => unreachable!(), }; memory_store_value = Some(value); @@ -835,11 +916,19 @@ impl<'a> Runtime<'a> { let syscall = SyscallCode::from_u32(syscall_id); if self.print_report && !self.unconstrained { - self.report - .syscall_counts - .entry(syscall) - .and_modify(|c| *c += 1) - .or_insert(1); + self.report.syscall_counts.entry(syscall).and_modify(|c| *c += 1).or_insert(1); + } + + // `hint_slice` is allowed in unconstrained mode since it is used to write the hint. + // Other syscalls are not allowed because they can lead to non-deterministic + // behavior, especially since many syscalls modify memory in place, + // which is not permitted in unconstrained mode. This will result in + // non-zero memory interactions when generating a proof. + + if self.unconstrained + && (syscall != SyscallCode::EXIT_UNCONSTRAINED && syscall != SyscallCode::WRITE) + { + return Err(ExecutionError::InvalidSyscallUsage(syscall_id as u64)); } let syscall_impl = self.get_syscall(syscall).cloned(); @@ -847,8 +936,9 @@ impl<'a> Runtime<'a> { precompile_rt.syscall_lookup_id = syscall_lookup_id; let (precompile_next_pc, precompile_cycles, returned_exit_code) = if let Some(syscall_impl) = syscall_impl { - // Executing a syscall optionally returns a value to write to the t0 register. - // If it returns None, we just keep the syscall_id in t0. + // Executing a syscall optionally returns a value to write to the t0 + // register. If it returns None, we just keep the + // syscall_id in t0. let res = syscall_impl.execute(&mut precompile_rt, b, c); if let Some(val) = res { a = val; @@ -882,18 +972,13 @@ impl<'a> Runtime<'a> { exit_code = returned_exit_code; // Update the syscall counts. - let syscall_count = self.state.syscall_counts.entry(syscall).or_insert(0); - let (threshold, multiplier) = match syscall { - SyscallCode::KECCAK_PERMUTE => { - (self.opts.split_opts.keccak_split_threshold, 24) - } - SyscallCode::SHA_EXTEND => { - (self.opts.split_opts.sha_extend_split_threshold, 48) - } - SyscallCode::SHA_COMPRESS => { - (self.opts.split_opts.sha_compress_split_threshold, 80) - } - _ => (self.opts.split_opts.deferred_shift_threshold, 1), + let syscall_for_count = syscall.count_map(); + let syscall_count = self.state.syscall_counts.entry(syscall_for_count).or_insert(0); + let (threshold, multiplier) = match syscall_for_count { + SyscallCode::KECCAK_PERMUTE => (self.opts.split_opts.keccak, 24), + SyscallCode::SHA_EXTEND => (self.opts.split_opts.sha_extend, 48), + SyscallCode::SHA_COMPRESS => (self.opts.split_opts.sha_compress, 80), + _ => (self.opts.split_opts.deferred, 1), }; let nonce = (((*syscall_count as usize) % threshold) * multiplier) as u32; self.record.nonce_lookup.insert(syscall_lookup_id, nonce); @@ -981,14 +1066,14 @@ impl<'a> Runtime<'a> { } // Emit the CPU event for this cycle. - if self.emit_events { + if self.executor_mode == ExecutorMode::Trace { self.emit_cpu( self.shard(), channel, clk, pc, next_pc, - instruction, + *instruction, a, b, c, @@ -1012,7 +1097,7 @@ impl<'a> Runtime<'a> { self.log(&instruction); // Execute the instruction. - self.execute_instruction(instruction)?; + self.execute_instruction(&instruction)?; // Increment the clock. self.state.global_clk += 1; @@ -1038,6 +1123,7 @@ impl<'a> Runtime<'a> { >= (self.program.instructions.len() * 4) as u32) } + /// Bump the record. pub fn bump_record(&mut self) { let removed_record = std::mem::replace(&mut self.record, ExecutionRecord::new(self.program.clone())); @@ -1046,21 +1132,59 @@ impl<'a> Runtime<'a> { self.records.push(removed_record); } - /// Execute up to `self.shard_batch_size` cycles, returning the events emitted and whether the program ended. + /// Execute up to `self.shard_batch_size` cycles, returning the events emitted and whether the + /// program ended. + /// + /// # Errors + /// + /// This function will return an error if the program execution fails. pub fn execute_record(&mut self) -> Result<(Vec, bool), ExecutionError> { - self.emit_events = true; + self.executor_mode = ExecutorMode::Trace; self.print_report = true; let done = self.execute()?; Ok((std::mem::take(&mut self.records), done)) } - /// Execute up to `self.shard_batch_size` cycles, returning a copy of the prestate and whether the program ended. + /// Execute up to `self.shard_batch_size` cycles, returning the checkpoint from before execution + /// and whether the program ended. + /// + /// # Errors + /// + /// This function will return an error if the program execution fails. pub fn execute_state(&mut self) -> Result<(ExecutionState, bool), ExecutionError> { - self.emit_events = false; - self.print_report = false; - let state = self.state.clone(); - let done = self.execute()?; - Ok((state, done)) + self.memory_checkpoint.clear(); + self.executor_mode = ExecutorMode::Checkpoint; + self.print_report = true; + + // Take memory out and then clone so that memory is not cloned. + let memory = std::mem::take(&mut self.state.memory); + let mut checkpoint = tracing::info_span!("clone").in_scope(|| self.state.clone()); + self.state.memory = memory; + + let done = tracing::info_span!("execute").in_scope(|| self.execute())?; + // Create a checkpoint using `memory_checkpoint`. Just include all memory if `done` since we + // need it all for MemoryFinalize. + tracing::info_span!("create memory checkpoint").in_scope(|| { + let memory_checkpoint = std::mem::take(&mut self.memory_checkpoint); + if done { + // If we're done, we need to include all memory. But we need to reset any modified + // memory to as it was before the execution. + checkpoint.memory.clone_from(&self.state.memory); + memory_checkpoint.into_iter().for_each(|(addr, record)| { + if let Some(record) = record { + checkpoint.memory.insert(addr, record); + } else { + checkpoint.memory.remove(&addr); + } + }); + } else { + checkpoint.memory = memory_checkpoint + .into_iter() + .filter_map(|(addr, record)| record.map(|record| (addr, record))) + .collect(); + } + }); + Ok((checkpoint, done)) } fn initialize(&mut self) { @@ -1068,38 +1192,37 @@ impl<'a> Runtime<'a> { self.state.channel = 0; tracing::debug!("loading memory image"); - for (addr, value) in self.program.memory_image.iter() { - self.state.memory.insert( - *addr, - MemoryRecord { - value: *value, - shard: 0, - timestamp: 0, - }, - ); + for (addr, value) in &self.program.memory_image { + self.state.memory.insert(*addr, MemoryRecord { value: *value, shard: 0, timestamp: 0 }); } } - pub fn run_untraced(&mut self) -> Result<(), ExecutionError> { - self.emit_events = false; + /// Executes the program without tracing and without emitting events. + /// + /// # Errors + /// + /// This function will return an error if the program execution fails. + pub fn run_fast(&mut self) -> Result<(), ExecutionError> { + self.executor_mode = ExecutorMode::Simple; self.print_report = true; while !self.execute()? {} Ok(()) } + /// Executes the program and prints the execution report. + /// + /// # Errors + /// + /// This function will return an error if the program execution fails. pub fn run(&mut self) -> Result<(), ExecutionError> { - self.emit_events = true; + self.executor_mode = ExecutorMode::Trace; self.print_report = true; while !self.execute()? {} Ok(()) } - pub fn dry_run(&mut self) { - self.emit_events = false; - while !self.execute().unwrap() {} - } - - /// Executes up to `self.shard_batch_size` cycles of the program, returning whether the program has finished. + /// Executes up to `self.shard_batch_size` cycles of the program, returning whether the program + /// has finished. fn execute(&mut self) -> Result { // Get the program. let program = self.program.clone(); @@ -1112,7 +1235,8 @@ impl<'a> Runtime<'a> { self.initialize(); } - // Loop until we've executed `self.shard_batch_size` shards if `self.shard_batch_size` is set. + // Loop until we've executed `self.shard_batch_size` shards if `self.shard_batch_size` is + // set. let mut done = false; let mut current_shard = self.state.current_shard; let mut num_shards_executed = 0; @@ -1155,16 +1279,16 @@ impl<'a> Runtime<'a> { record.public_values.committed_value_digest = public_values.committed_value_digest; record.public_values.deferred_proofs_digest = public_values.deferred_proofs_digest; record.public_values.execution_shard = start_shard + i as u32; - if !record.cpu_events.is_empty() { + if record.cpu_events.is_empty() { + record.public_values.start_pc = last_next_pc; + record.public_values.next_pc = last_next_pc; + record.public_values.exit_code = last_exit_code; + } else { record.public_values.start_pc = record.cpu_events[0].pc; record.public_values.next_pc = record.cpu_events.last().unwrap().next_pc; record.public_values.exit_code = record.cpu_events.last().unwrap().exit_code; last_next_pc = record.public_values.next_pc; last_exit_code = record.public_values.exit_code; - } else { - record.public_values.start_pc = last_next_pc; - record.public_values.next_pc = last_next_pc; - record.public_values.exit_code = last_exit_code; } } @@ -1173,14 +1297,14 @@ impl<'a> Runtime<'a> { fn postprocess(&mut self) { // Flush remaining stdout/stderr - for (fd, buf) in self.io_buf.iter() { + for (fd, buf) in &self.io_buf { if !buf.is_empty() { match fd { 1 => { - println!("stdout: {}", buf); + println!("stdout: {buf}"); } 2 => { - println!("stderr: {}", buf); + println!("stderr: {buf}"); } _ => {} } @@ -1193,13 +1317,13 @@ impl<'a> Runtime<'a> { } // Ensure that all proofs and input bytes were read, otherwise warn the user. - if self.state.proof_stream_ptr != self.state.proof_stream.len() { - panic!( - "Not all proofs were read. Proving will fail during recursion. Did you pass too many proofs in or forget to call verify_sp1_proof?" - ); - } + // if self.state.proof_stream_ptr != self.state.proof_stream.len() { + // panic!( + // "Not all proofs were read. Proving will fail during recursion. Did you pass too + // many proofs in or forget to call verify_sp1_proof?" ); + // } if self.state.input_stream_ptr != self.state.input_stream.len() { - log::warn!("Not all input bytes were read."); + tracing::warn!("Not all input bytes were read."); } // SECTION: Set up all MemoryInitializeFinalizeEvents needed for memory argument. @@ -1211,30 +1335,25 @@ impl<'a> Runtime<'a> { let addr_0_final_record = match addr_0_record { Some(record) => record, - None => &MemoryRecord { - value: 0, - shard: 0, - timestamp: 1, - }, + None => &MemoryRecord { value: 0, shard: 0, timestamp: 1 }, }; - memory_finalize_events.push(MemoryInitializeFinalizeEvent::finalize_from_record( - 0, - addr_0_final_record, - )); + memory_finalize_events + .push(MemoryInitializeFinalizeEvent::finalize_from_record(0, addr_0_final_record)); let memory_initialize_events = &mut self.record.memory_initialize_events; let addr_0_initialize_event = MemoryInitializeFinalizeEvent::initialize(0, 0, addr_0_record.is_some()); memory_initialize_events.push(addr_0_initialize_event); + self.report.touched_memory_addresses = self.state.memory.len() as u64; for addr in self.state.memory.keys() { if addr == &0 { // Handled above. continue; } - // Program memory is initialized in the MemoryProgram chip and doesn't require any events, - // so we only send init events for other memory addresses. + // Program memory is initialized in the MemoryProgram chip and doesn't require any + // events, so we only send init events for other memory addresses. if !self.record.program.memory_image.contains_key(addr) { let initial_value = self.state.uninitialized_memory.get(addr).unwrap_or(&0); memory_initialize_events.push(MemoryInitializeFinalizeEvent::initialize( @@ -1245,71 +1364,95 @@ impl<'a> Runtime<'a> { } let record = *self.state.memory.get(addr).unwrap(); - memory_finalize_events.push(MemoryInitializeFinalizeEvent::finalize_from_record( - *addr, &record, - )); + memory_finalize_events + .push(MemoryInitializeFinalizeEvent::finalize_from_record(*addr, &record)); } } fn get_syscall(&mut self, code: SyscallCode) -> Option<&Arc> { self.syscall_map.get(&code) } -} - -#[cfg(test)] -pub mod tests { - - use crate::{ - runtime::Register, - utils::{ - tests::{FIBONACCI_ELF, KECCAK_PERMUTE_ELF, PANIC_ELF}, - SP1CoreOpts, - }, - }; - use super::{Instruction, Opcode, Program, Runtime}; + #[inline] + fn log(&mut self, _: &Instruction) { + // Write the current program counter to the trace buffer for the cycle tracer. + if let Some(ref mut buf) = self.trace_buf { + if !self.unconstrained { + buf.write_all(&u32::to_be_bytes(self.state.pc)).unwrap(); + } + } - pub fn simple_program() -> Program { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 0, 37, false, true), - Instruction::new(Opcode::ADD, 31, 30, 29, false, false), - ]; - Program::new(instructions, 0, 0) + if !self.unconstrained && self.state.global_clk % 10_000_000 == 0 { + log::info!("clk = {} pc = 0x{:x?}", self.state.global_clk, self.state.pc); + } } +} - pub fn fibonacci_program() -> Program { - Program::from(FIBONACCI_ELF) +impl Default for ExecutorMode { + fn default() -> Self { + Self::Simple } +} - pub fn ssz_withdrawals_program() -> Program { - Program::from(KECCAK_PERMUTE_ELF) - } +// TODO: FIX +/// Aligns an address to the nearest word below or equal to it. +#[must_use] +pub const fn align(addr: u32) -> u32 { + addr - addr % 4 +} - pub fn panic_program() -> Program { - Program::from(PANIC_ELF) - } +// TODO: FIX +/// The number of different byte lookup channels. +pub const NUM_BYTE_LOOKUP_CHANNELS: u8 = 16; + +#[cfg(test)] +mod tests { + + use sp1_stark::SP1CoreOpts; + + use crate::programs::tests::{ + fibonacci_program, panic_program, simple_memory_program, simple_program, + ssz_withdrawals_program, + }; + + use crate::Register; + + use super::{Executor, Instruction, Opcode, Program}; fn _assert_send() {} /// Runtime needs to be Send so we can use it across async calls. fn _assert_runtime_is_send() { - _assert_send::(); + _assert_send::(); } #[test] fn test_simple_program_run() { let program = simple_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 42); } + #[test] + fn test_fibonacci_program_run() { + let program = fibonacci_program(); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); + runtime.run().unwrap(); + } + + #[test] + fn test_ssz_withdrawals_program_run() { + let program = ssz_withdrawals_program(); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); + runtime.run().unwrap(); + } + #[test] #[should_panic] fn test_panic() { let program = panic_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); } @@ -1325,7 +1468,7 @@ pub mod tests { Instruction::new(Opcode::ADD, 31, 30, 29, false, false), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 42); } @@ -1342,7 +1485,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 32); } @@ -1359,7 +1502,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 32); } @@ -1376,7 +1519,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 37); @@ -1394,7 +1537,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 5); } @@ -1411,7 +1554,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1184); } @@ -1428,7 +1571,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1); } @@ -1445,7 +1588,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 1); } @@ -1462,7 +1605,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1479,7 +1622,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1496,7 +1639,7 @@ pub mod tests { ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 84); } @@ -1508,11 +1651,11 @@ pub mod tests { // addi x31, x30, 4 let instructions = vec![ Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 29, 0xffffffff, false, true), + Instruction::new(Opcode::ADD, 30, 29, 0xFFFF_FFFF, false, true), Instruction::new(Opcode::ADD, 31, 30, 4, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 5 - 1 + 4); } @@ -1528,7 +1671,7 @@ pub mod tests { Instruction::new(Opcode::XOR, 31, 30, 42, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 10); } @@ -1544,7 +1687,7 @@ pub mod tests { Instruction::new(Opcode::OR, 31, 30, 42, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 47); } @@ -1560,7 +1703,7 @@ pub mod tests { Instruction::new(Opcode::AND, 31, 30, 42, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1574,7 +1717,7 @@ pub mod tests { Instruction::new(Opcode::SLL, 31, 29, 4, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 80); } @@ -1588,7 +1731,7 @@ pub mod tests { Instruction::new(Opcode::SRL, 31, 29, 4, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 2); } @@ -1602,7 +1745,7 @@ pub mod tests { Instruction::new(Opcode::SRA, 31, 29, 4, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 2); } @@ -1616,7 +1759,7 @@ pub mod tests { Instruction::new(Opcode::SLT, 31, 29, 37, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1630,7 +1773,7 @@ pub mod tests { Instruction::new(Opcode::SLTU, 31, 29, 37, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.register(Register::X31), 0); } @@ -1649,7 +1792,7 @@ pub mod tests { Instruction::new(Opcode::JALR, 5, 11, 8, false, true), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.registers()[Register::X5 as usize], 8); assert_eq!(runtime.registers()[Register::X11 as usize], 100); @@ -1663,12 +1806,13 @@ pub mod tests { Instruction::new(opcode, 12, 10, 11, false, false), ]; let program = Program::new(instructions, 0, 0); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); assert_eq!(runtime.registers()[Register::X12 as usize], expected); } #[test] + #[allow(clippy::unreadable_literal)] fn multiplication_tests() { simple_op_code_test(Opcode::MULHU, 0x00000000, 0x00000000, 0x00000000); simple_op_code_test(Opcode::MULHU, 0x00000000, 0x00000001, 0x00000001); @@ -1732,7 +1876,7 @@ pub mod tests { #[test] fn division_tests() { simple_op_code_test(Opcode::DIVU, 3, 20, 6); - simple_op_code_test(Opcode::DIVU, 715827879, u32::MAX - 20 + 1, 6); + simple_op_code_test(Opcode::DIVU, 715_827_879, u32::MAX - 20 + 1, 6); simple_op_code_test(Opcode::DIVU, 0, 20, u32::MAX - 6 + 1); simple_op_code_test(Opcode::DIVU, 0, u32::MAX - 20 + 1, u32::MAX - 6 + 1); @@ -1775,6 +1919,7 @@ pub mod tests { } #[test] + #[allow(clippy::unreadable_literal)] fn shift_tests() { simple_op_code_test(Opcode::SLL, 0x00000001, 0x00000001, 0); simple_op_code_test(Opcode::SLL, 0x00000002, 0x00000001, 1); @@ -1835,53 +1980,11 @@ pub mod tests { simple_op_code_test(Opcode::SRA, 0xffffffff, 0x81818181, 31); } - pub fn simple_memory_program() -> Program { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 0x12348765, false, true), - // SW and LW - Instruction::new(Opcode::SW, 29, 0, 0x27654320, false, true), - Instruction::new(Opcode::LW, 28, 0, 0x27654320, false, true), - // LBU - Instruction::new(Opcode::LBU, 27, 0, 0x27654320, false, true), - Instruction::new(Opcode::LBU, 26, 0, 0x27654321, false, true), - Instruction::new(Opcode::LBU, 25, 0, 0x27654322, false, true), - Instruction::new(Opcode::LBU, 24, 0, 0x27654323, false, true), - // LB - Instruction::new(Opcode::LB, 23, 0, 0x27654320, false, true), - Instruction::new(Opcode::LB, 22, 0, 0x27654321, false, true), - // LHU - Instruction::new(Opcode::LHU, 21, 0, 0x27654320, false, true), - Instruction::new(Opcode::LHU, 20, 0, 0x27654322, false, true), - // LU - Instruction::new(Opcode::LH, 19, 0, 0x27654320, false, true), - Instruction::new(Opcode::LH, 18, 0, 0x27654322, false, true), - // SB - Instruction::new(Opcode::ADD, 17, 0, 0x38276525, false, true), - // Save the value 0x12348765 into address 0x43627530 - Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true), - Instruction::new(Opcode::SB, 17, 0, 0x43627530, false, true), - Instruction::new(Opcode::LW, 16, 0, 0x43627530, false, true), - Instruction::new(Opcode::SB, 17, 0, 0x43627531, false, true), - Instruction::new(Opcode::LW, 15, 0, 0x43627530, false, true), - Instruction::new(Opcode::SB, 17, 0, 0x43627532, false, true), - Instruction::new(Opcode::LW, 14, 0, 0x43627530, false, true), - Instruction::new(Opcode::SB, 17, 0, 0x43627533, false, true), - Instruction::new(Opcode::LW, 13, 0, 0x43627530, false, true), - // SH - // Save the value 0x12348765 into address 0x43627530 - Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true), - Instruction::new(Opcode::SH, 17, 0, 0x43627530, false, true), - Instruction::new(Opcode::LW, 12, 0, 0x43627530, false, true), - Instruction::new(Opcode::SH, 17, 0, 0x43627532, false, true), - Instruction::new(Opcode::LW, 11, 0, 0x43627530, false, true), - ]; - Program::new(instructions, 0, 0) - } - #[test] + #[allow(clippy::unreadable_literal)] fn test_simple_memory_program_run() { let program = simple_memory_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); // Assert SW & LW case diff --git a/core/src/runtime/hooks.rs b/crates/core/executor/src/hook.rs similarity index 79% rename from core/src/runtime/hooks.rs rename to crates/core/executor/src/hook.rs index 16158aab24..d04bd92231 100644 --- a/core/src/runtime/hooks.rs +++ b/crates/core/executor/src/hook.rs @@ -1,12 +1,11 @@ use core::fmt::Debug; -use std::collections::HashMap; use std::sync::{Arc, RwLock, RwLockWriteGuard}; -use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; -use k256::elliptic_curve::ops::Invert; +use hashbrown::HashMap; +use sp1_curves::k256::{Invert, RecoveryId, Signature, VerifyingKey}; -use super::Runtime; +use crate::Executor; /// A runtime hook, wrapped in a smart pointer. pub type BoxedHook<'a> = Arc>; @@ -47,23 +46,26 @@ pub struct HookRegistry<'a> { } impl<'a> HookRegistry<'a> { - /// Create a registry with the default hooks. + /// Create a default [`HookRegistry`]. + #[must_use] pub fn new() -> Self { - Default::default() + HookRegistry::default() } - /// Create an empty registry. + /// Create an empty [`HookRegistry`]. + #[must_use] pub fn empty() -> Self { - Self { - table: Default::default(), - } + Self { table: HashMap::default() } } /// Get a hook with exclusive write access, if it exists. - /// Should not be called in async contexts, unless you know what you are doing. - pub fn get(&self, fd: &u32) -> Option> { + /// + /// Note: This function should not be called in async contexts, unless you know what you are + /// doing. + #[must_use] + pub fn get(&self, fd: u32) -> Option> { // Calling `.unwrap()` panics on a poisoned lock. Should never happen normally. - self.table.get(fd).map(|x| x.write().unwrap()) + self.table.get(&fd).map(|x| x.write().unwrap()) } } @@ -95,7 +97,8 @@ impl<'a> Debug for HookRegistry<'a> { /// Environment that a hook may read from. pub struct HookEnv<'a, 'b: 'a> { - pub runtime: &'a Runtime<'b>, + /// The runtime. + pub runtime: &'a Executor<'b>, } /// Recovers the public key from the signature and message hash using the k256 crate. @@ -113,12 +116,9 @@ pub struct HookEnv<'a, 'b: 'a> { /// /// WARNING: This function is used to recover the public key outside of the zkVM context. These /// values must be constrained by the zkVM for correctness. -pub fn hook_ecrecover(_env: HookEnv, buf: &[u8]) -> Vec> { - assert_eq!( - buf.len(), - 65 + 32, - "ecrecover input should have length 65 + 32" - ); +#[must_use] +pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { + assert_eq!(buf.len(), 65 + 32, "ecrecover input should have length 65 + 32"); let (sig, msg_hash) = buf.split_at(65); let sig: &[u8; 65] = sig.try_into().unwrap(); let msg_hash: &[u8; 32] = msg_hash.try_into().unwrap(); @@ -128,7 +128,7 @@ pub fn hook_ecrecover(_env: HookEnv, buf: &[u8]) -> Vec> { if let Some(sig_normalized) = sig.normalize_s() { sig = sig_normalized; - recovery_id ^= 1 + recovery_id ^= 1; }; let recid = RecoveryId::from_byte(recovery_id).expect("Computed recovery ID is invalid!"); @@ -143,18 +143,12 @@ pub fn hook_ecrecover(_env: HookEnv, buf: &[u8]) -> Vec> { #[cfg(test)] pub mod tests { - use crate::{ - runtime::Program, - stark::CpuProver, - utils::{self, tests::ECRECOVER_ELF}, - }; - use super::*; #[test] pub fn hook_fds_match() { use sp1_zkvm::lib::io; - assert_eq!(FD_ECRECOVER_HOOK, io::FD_ECRECOVER_HOOK) + assert_eq!(FD_ECRECOVER_HOOK, io::FD_ECRECOVER_HOOK); } #[test] @@ -167,11 +161,4 @@ pub mod tests { pub fn registry_empty_is_empty() { assert_eq!(HookRegistry::empty().table.len(), 0); } - - #[test] - fn test_ecrecover_program_prove() { - utils::setup_logger(); - let program = Program::from(ECRECOVER_ELF); - utils::run_test::>(program).unwrap(); - } } diff --git a/core/src/runtime/instruction.rs b/crates/core/executor/src/instruction.rs similarity index 73% rename from core/src/runtime/instruction.rs rename to crates/core/executor/src/instruction.rs index 9f8c7533c5..bc1df27ba0 100644 --- a/core/src/runtime/instruction.rs +++ b/crates/core/executor/src/instruction.rs @@ -1,21 +1,34 @@ +//! Instructions for the SP1 zkVM. + use core::fmt::Debug; use serde::{Deserialize, Serialize}; -use super::Opcode; +use crate::opcode::Opcode; -/// An instruction specifies an operation to execute and the operands. +/// RISC-V 32IM Instruction. +/// +/// The structure of the instruction differs from the RISC-V ISA. We do not encode the instructions +/// as 32-bit words, but instead use a custom encoding that is more friendly to decode in the +/// SP1 zkVM. #[derive(Clone, Copy, Serialize, Deserialize)] pub struct Instruction { + /// The operation to execute. pub opcode: Opcode, + /// The first operand. pub op_a: u32, + /// The second operand. pub op_b: u32, + /// The third operand. pub op_c: u32, + /// Whether the second operand is an immediate value. pub imm_b: bool, + /// Whether the third operand is an immediate value. pub imm_c: bool, } impl Instruction { - /// Create a new instruction. + /// Create a new [`RiscvInstruction`]. + #[must_use] pub const fn new( opcode: Opcode, op_a: u32, @@ -24,17 +37,11 @@ impl Instruction { imm_b: bool, imm_c: bool, ) -> Self { - Self { - opcode, - op_a, - op_b, - op_c, - imm_b, - imm_c, - } + Self { opcode, op_a, op_b, op_c, imm_b, imm_c } } /// Returns if the instruction is an ALU instruction. + #[must_use] pub const fn is_alu_instruction(&self) -> bool { matches!( self.opcode, @@ -60,11 +67,13 @@ impl Instruction { } /// Returns if the instruction is a ecall instruction. + #[must_use] pub fn is_ecall_instruction(&self) -> bool { self.opcode == Opcode::ECALL } /// Returns if the instruction is a memory instruction. + #[must_use] pub const fn is_memory_instruction(&self) -> bool { matches!( self.opcode, @@ -80,6 +89,7 @@ impl Instruction { } /// Returns if the instruction is a branch instruction. + #[must_use] pub const fn is_branch_instruction(&self) -> bool { matches!( self.opcode, @@ -88,6 +98,7 @@ impl Instruction { } /// Returns if the instruction is a jump instruction. + #[must_use] pub const fn is_jump_instruction(&self) -> bool { matches!(self.opcode, Opcode::JAL | Opcode::JALR) } @@ -102,21 +113,13 @@ impl Debug for Instruction { } else { format!("%x{}", self.op_b) }; - let op_c_formatted = if self.imm_c { - format!("{}", self.op_c as i32) - } else { - format!("%x{}", self.op_c) - }; + let op_c_formatted = + if self.imm_c { format!("{}", self.op_c as i32) } else { format!("%x{}", self.op_c) }; let width = 10; write!( f, - "{: Read for Executor<'a> { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.read_public_values_slice(buf); + Ok(buf.len()) + } +} + +impl<'a> Executor<'a> { + /// Write a serializable input to the standard input stream. + pub fn write_stdin(&mut self, input: &T) { + let mut buf = Vec::new(); + bincode::serialize_into(&mut buf, input).expect("serialization failed"); + self.state.input_stream.push(buf); + } + + /// Write a slice of bytes to the standard input stream. + pub fn write_stdin_slice(&mut self, input: &[u8]) { + self.state.input_stream.push(input.to_vec()); + } + + /// Write a slice of vecs to the standard input stream. + pub fn write_vecs(&mut self, inputs: &[Vec]) { + for input in inputs { + self.state.input_stream.push(input.clone()); + } + } + + /// Write a proof and verifying key to the proof stream. + pub fn write_proof( + &mut self, + proof: ShardProof, + vk: StarkVerifyingKey, + ) { + self.state.proof_stream.push((proof, vk)); + } + + /// Read a serializable public values from the public values stream. + pub fn read_public_values(&mut self) -> T { + let result = bincode::deserialize_from::<_, T>(self); + result.unwrap() + } + + /// Read a slice of bytes from the public values stream. + pub fn read_public_values_slice(&mut self, buf: &mut [u8]) { + let len = buf.len(); + let start = self.state.public_values_stream_ptr; + let end = start + len; + assert!(end <= self.state.public_values_stream.len()); + buf.copy_from_slice(&self.state.public_values_stream[start..end]); + self.state.public_values_stream_ptr = end; + } +} diff --git a/crates/core/executor/src/lib.rs b/crates/core/executor/src/lib.rs new file mode 100644 index 0000000000..e45a5ea6c7 --- /dev/null +++ b/crates/core/executor/src/lib.rs @@ -0,0 +1,49 @@ +//! An implementation of an exucutor for the SP1 RISC-V zkVM. + +#![warn(clippy::pedantic)] +#![allow(clippy::similar_names)] +#![allow(clippy::cast_possible_wrap)] +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_sign_loss)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::needless_range_loop)] +#![allow(clippy::cast_lossless)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::should_panic_without_expect)] +#![allow(clippy::field_reassign_with_default)] +#![allow(clippy::manual_assert)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::explicit_iter_loop)] +#![warn(missing_docs)] + +mod context; +mod disassembler; +pub mod events; +mod executor; +mod hook; +mod instruction; +mod io; +mod opcode; +mod program; +#[cfg(any(test, feature = "programs"))] +pub mod programs; +mod record; +mod register; +mod report; +mod state; +pub mod subproof; +pub mod syscalls; + +pub use context::*; +pub use executor::*; +pub use hook::*; +pub use instruction::*; +pub use opcode::*; +pub use program::*; +pub use record::*; +pub use register::*; +pub use report::*; +pub use state::*; diff --git a/crates/core/executor/src/opcode.rs b/crates/core/executor/src/opcode.rs new file mode 100644 index 0000000000..868f516d49 --- /dev/null +++ b/crates/core/executor/src/opcode.rs @@ -0,0 +1,188 @@ +//! Opcodes for the SP1 zkVM. + +use std::fmt::Display; + +use p3_field::Field; +use serde::{Deserialize, Serialize}; + +/// An opcode (short for "operation code") specifies the operation to be perfomed by the processor. +/// +/// In the context of the RISC-V ISA, an opcode specifies which operation (i.e., addition, +/// subtraction, multiplication, etc.) to perform on up to three operands such as registers, +/// immediates, or memory addresses. +/// +/// While the SP1 zkVM targets the RISC-V ISA, it uses a custom instruction encoding that uses +/// a different set of opcodes. The main difference is that the SP1 zkVM encodes register +/// operations and immediate operations as the same opcode. For example, the RISC-V opcodes ADD and +/// ADDI both become ADD inside the SP1 zkVM. We utilize flags inside the instruction itself to +/// distinguish between the two. +/// +/// Refer to the "RV32I Reference Card" [here](https://github.com/johnwinans/rvalp/releases) for +/// more details. +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +pub enum Opcode { + /// rd ← rs1 + rs2, pc ← pc + 4 + ADD = 0, + /// rd ← rs1 - rs2, pc ← pc + 4 + SUB = 1, + /// rd ← rs1 ^ rs2, pc ← pc + 4 + XOR = 2, + /// rd ← rs1 | rs2, pc ← pc + 4 + OR = 3, + /// rd ← rs1 & rs2, pc ← pc + 4 + AND = 4, + /// rd ← rs1 << rs2, pc ← pc + 4 + SLL = 5, + /// rd ← rs1 >> rs2 (logical), pc ← pc + 4 + SRL = 6, + /// rd ← rs1 >> rs2 (arithmetic), pc ← pc + 4 + SRA = 7, + /// rd ← (rs1 < rs2) ? 1 : 0 (signed), pc ← pc + 4 + SLT = 8, + /// rd ← (rs1 < rs2) ? 1 : 0 (unsigned), pc ← pc + 4 + SLTU = 9, + /// rd ← sx(m8(rs1 + imm)), pc ← pc + 4 + LB = 10, + /// rd ← sx(m16(rs1 + imm)), pc ← pc + 4 + LH = 11, + /// rd ← sx(m32(rs1 + imm)), pc ← pc + 4 + LW = 12, + /// rd ← zx(m8(rs1 + imm)), pc ← pc + 4 + LBU = 13, + /// rd ← zx(m16(rs1 + imm)), pc ← pc + 4 + LHU = 14, + /// m8(rs1 + imm) ← rs2[7:0], pc ← pc + 4 + SB = 15, + /// m16(rs1 + imm) ← rs2[15:0], pc ← pc + 4 + SH = 16, + /// m32(rs1 + imm) ← rs2[31:0], pc ← pc + 4 + SW = 17, + /// pc ← pc + ((rs1 == rs2) ? imm : 4) + BEQ = 18, + /// pc ← pc + ((rs1 != rs2) ? imm : 4) + BNE = 19, + /// pc ← pc + ((rs1 < rs2) ? imm : 4) (signed) + BLT = 20, + /// pc ← pc + ((rs1 >= rs2) ? imm : 4) (signed) + BGE = 21, + /// pc ← pc + ((rs1 < rs2) ? imm : 4) (unsigned) + BLTU = 22, + /// pc ← pc + ((rs1 >= rs2) ? imm : 4) (unsigned) + BGEU = 23, + /// rd ← pc + 4, pc ← pc + imm + JAL = 24, + /// rd ← pc + 4, pc ← (rs1 + imm) & ∼1 + JALR = 25, + /// rd ← pc + imm, pc ← pc + 4 + AUIPC = 27, + /// Transfer control to the debugger. + ECALL = 28, + /// Transfer control to the operating system. + EBREAK = 29, + /// rd ← rs1 * rs2 (signed), pc ← pc + 4 + MUL = 30, + /// rd ← rs1 * rs2 (half), pc ← pc + 4 + MULH = 31, + /// rd ← rs1 * rs2 (half unsigned), pc ← pc + 4 + MULHU = 32, + /// rd ← rs1 * rs2 (half signed unsigned), pc ← pc + 4 + MULHSU = 33, + /// rd ← rs1 / rs2 (signed), pc ← pc + 4 + DIV = 34, + /// rd ← rs1 / rs2 (unsigned), pc ← pc + 4 + DIVU = 35, + /// rd ← rs1 % rs2 (signed), pc ← pc + 4 + REM = 36, + /// rd ← rs1 % rs2 (unsigned), pc ← pc + 4 + REMU = 37, + /// Unimplemented instruction. + UNIMP = 39, +} + +/// Byte Opcode. +/// +/// This represents a basic operation that can be performed on a byte. Usually, these operations +/// are performed via lookup tables on that iterate over the domain of two 8-bit values. The +/// operations include both bitwise operations (AND, OR, XOR) as well as basic arithmetic. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[allow(clippy::upper_case_acronyms)] +pub enum ByteOpcode { + /// Bitwise AND. + AND = 0, + /// Bitwise OR. + OR = 1, + /// Bitwise XOR. + XOR = 2, + /// Shift Left Logical. + SLL = 3, + /// Unsigned 8-bit Range Check. + U8Range = 4, + /// Shift Right with Carry. + ShrCarry = 5, + /// Unsigned Less Than. + LTU = 6, + /// Most Significant Bit. + MSB = 7, + /// Unsigned 16-bit Range Check. + U16Range = 8, +} + +impl Opcode { + /// Get the mnemonic for the opcode. + #[must_use] + pub const fn mnemonic(&self) -> &str { + match self { + Opcode::ADD => "add", + Opcode::SUB => "sub", + Opcode::XOR => "xor", + Opcode::OR => "or", + Opcode::AND => "and", + Opcode::SLL => "sll", + Opcode::SRL => "srl", + Opcode::SRA => "sra", + Opcode::SLT => "slt", + Opcode::SLTU => "sltu", + Opcode::LB => "lb", + Opcode::LH => "lh", + Opcode::LW => "lw", + Opcode::LBU => "lbu", + Opcode::LHU => "lhu", + Opcode::SB => "sb", + Opcode::SH => "sh", + Opcode::SW => "sw", + Opcode::BEQ => "beq", + Opcode::BNE => "bne", + Opcode::BLT => "blt", + Opcode::BGE => "bge", + Opcode::BLTU => "bltu", + Opcode::BGEU => "bgeu", + Opcode::JAL => "jal", + Opcode::JALR => "jalr", + Opcode::AUIPC => "auipc", + Opcode::ECALL => "ecall", + Opcode::EBREAK => "ebreak", + Opcode::MUL => "mul", + Opcode::MULH => "mulh", + Opcode::MULHU => "mulhu", + Opcode::MULHSU => "mulhsu", + Opcode::DIV => "div", + Opcode::DIVU => "divu", + Opcode::REM => "rem", + Opcode::REMU => "remu", + Opcode::UNIMP => "unimp", + } + } + + /// Convert the opcode to a field element. + #[must_use] + pub fn as_field(self) -> F { + F::from_canonical_u32(self as u32) + } +} + +impl Display for Opcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.mnemonic()) + } +} diff --git a/crates/core/executor/src/program.rs b/crates/core/executor/src/program.rs new file mode 100644 index 0000000000..e0cfaf7c2e --- /dev/null +++ b/crates/core/executor/src/program.rs @@ -0,0 +1,74 @@ +//! Programs that can be executed by the SP1 zkVM. + +use std::{collections::BTreeMap, fs::File, io::Read}; + +use p3_field::Field; +use serde::{Deserialize, Serialize}; +use sp1_stark::air::MachineProgram; + +use crate::{ + disassembler::{transpile, Elf}, + instruction::Instruction, +}; + +/// A program that can be executed by the SP1 zkVM. +/// +/// Contains a series of instructions along with the initial memory image. It also contains the +/// start address and base address of the program. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Program { + /// The instructions of the program. + pub instructions: Vec, + /// The start address of the program. + pub pc_start: u32, + /// The base address of the program. + pub pc_base: u32, + /// The initial memory image, useful for global constants. + pub memory_image: BTreeMap, +} + +impl Program { + /// Create a new [Program]. + #[must_use] + pub const fn new(instructions: Vec, pc_start: u32, pc_base: u32) -> Self { + Self { instructions, pc_start, pc_base, memory_image: BTreeMap::new() } + } + + /// Disassemble a RV32IM ELF to a program that be executed by the VM. + /// + /// # Errors + /// + /// This function may return an error if the ELF is not valid. + pub fn from(input: &[u8]) -> eyre::Result { + // Decode the bytes as an ELF. + let elf = Elf::decode(input)?; + + // Transpile the RV32IM instructions. + let instructions = transpile(&elf.instructions); + + // Return the program. + Ok(Program { + instructions, + pc_start: elf.pc_start, + pc_base: elf.pc_base, + memory_image: elf.memory_image, + }) + } + + /// Disassemble a RV32IM ELF to a program that be executed by the VM from a file path. + /// + /// # Errors + /// + /// This function will return an error if the file cannot be opened or read. + pub fn from_elf(path: &str) -> eyre::Result { + let mut elf_code = Vec::new(); + File::open(path)?.read_to_end(&mut elf_code)?; + Program::from(&elf_code) + } +} + +impl MachineProgram for Program { + fn pc_start(&self) -> F { + F::from_canonical_u32(self.pc_start) + } +} diff --git a/crates/core/executor/src/programs.rs b/crates/core/executor/src/programs.rs new file mode 100644 index 0000000000..b20cade70e --- /dev/null +++ b/crates/core/executor/src/programs.rs @@ -0,0 +1,207 @@ +//! RV32IM ELFs used for testing. + +#[allow(dead_code)] +#[allow(missing_docs)] +pub mod tests { + use crate::{Instruction, Opcode, Program}; + + pub const CHESS_ELF: &[u8] = + include_bytes!("../../../../examples/chess/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const FIBONACCI_IO_ELF: &[u8] = + include_bytes!("../../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const IO_ELF: &[u8] = + include_bytes!("../../../../examples/io/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const JSON_ELF: &[u8] = + include_bytes!("../../../../examples/json/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const REGEX_ELF: &[u8] = + include_bytes!("../../../../examples/regex/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const RSA_ELF: &[u8] = + include_bytes!("../../../../examples/rsa/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const SSZ_WITHDRAWALS_ELF: &[u8] = include_bytes!( + "../../../../examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf" + ); + + pub const TENDERMINT_ELF: &[u8] = + include_bytes!("../../../../examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const FIBONACCI_ELF: &[u8] = + include_bytes!("../../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED25519_ELF: &[u8] = + include_bytes!("../../../../tests/ed25519/elf/riscv32im-succinct-zkvm-elf"); + + pub const CYCLE_TRACKER_ELF: &[u8] = + include_bytes!("../../../../tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED_ADD_ELF: &[u8] = + include_bytes!("../../../../tests/ed-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const KECCAK_PERMUTE_ELF: &[u8] = + include_bytes!("../../../../tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf"); + + pub const KECCAK256_ELF: &[u8] = + include_bytes!("../../../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_ADD_ELF: &[u8] = + include_bytes!("../../../../tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA_COMPRESS_ELF: &[u8] = + include_bytes!("../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA_EXTEND_ELF: &[u8] = + include_bytes!("../../../../tests/sha-extend/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA2_ELF: &[u8] = + include_bytes!("../../../../tests/sha2/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_ADD_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_ADD_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const UINT256_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const VERIFY_PROOF_ELF: &[u8] = + include_bytes!("../../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); + + pub const PANIC_ELF: &[u8] = + include_bytes!("../../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_FP_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_FP2_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_FP2_ADDSUB_ELF: &[u8] = + include_bytes!("../../../../tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_FP_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_FP2_ADDSUB_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_FP2_MUL_ELF: &[u8] = + include_bytes!("../../../../tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf"); + + #[must_use] + pub fn simple_program() -> Program { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 30, 0, 37, false, true), + Instruction::new(Opcode::ADD, 31, 30, 29, false, false), + ]; + Program::new(instructions, 0, 0) + } + + /// Get the fibonacci program. + /// + /// # Panics + /// + /// This function will panic if the program fails to load. + #[must_use] + pub fn fibonacci_program() -> Program { + Program::from(FIBONACCI_ELF).unwrap() + } + + /// Get the SSZ withdrawals program. + /// + /// # Panics + /// + /// This function will panic if the program fails to load. + #[must_use] + pub fn ssz_withdrawals_program() -> Program { + Program::from(KECCAK_PERMUTE_ELF).unwrap() + } + + /// Get the panic program. + /// + /// # Panics + /// + /// This function will panic if the program fails to load. + #[must_use] + pub fn panic_program() -> Program { + Program::from(PANIC_ELF).unwrap() + } + + #[must_use] + #[allow(clippy::unreadable_literal)] + pub fn simple_memory_program() -> Program { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 0x12348765, false, true), + // SW and LW + Instruction::new(Opcode::SW, 29, 0, 0x27654320, false, true), + Instruction::new(Opcode::LW, 28, 0, 0x27654320, false, true), + // LBU + Instruction::new(Opcode::LBU, 27, 0, 0x27654320, false, true), + Instruction::new(Opcode::LBU, 26, 0, 0x27654321, false, true), + Instruction::new(Opcode::LBU, 25, 0, 0x27654322, false, true), + Instruction::new(Opcode::LBU, 24, 0, 0x27654323, false, true), + // LB + Instruction::new(Opcode::LB, 23, 0, 0x27654320, false, true), + Instruction::new(Opcode::LB, 22, 0, 0x27654321, false, true), + // LHU + Instruction::new(Opcode::LHU, 21, 0, 0x27654320, false, true), + Instruction::new(Opcode::LHU, 20, 0, 0x27654322, false, true), + // LU + Instruction::new(Opcode::LH, 19, 0, 0x27654320, false, true), + Instruction::new(Opcode::LH, 18, 0, 0x27654322, false, true), + // SB + Instruction::new(Opcode::ADD, 17, 0, 0x38276525, false, true), + // Save the value 0x12348765 into address 0x43627530 + Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true), + Instruction::new(Opcode::SB, 17, 0, 0x43627530, false, true), + Instruction::new(Opcode::LW, 16, 0, 0x43627530, false, true), + Instruction::new(Opcode::SB, 17, 0, 0x43627531, false, true), + Instruction::new(Opcode::LW, 15, 0, 0x43627530, false, true), + Instruction::new(Opcode::SB, 17, 0, 0x43627532, false, true), + Instruction::new(Opcode::LW, 14, 0, 0x43627530, false, true), + Instruction::new(Opcode::SB, 17, 0, 0x43627533, false, true), + Instruction::new(Opcode::LW, 13, 0, 0x43627530, false, true), + // SH + // Save the value 0x12348765 into address 0x43627530 + Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true), + Instruction::new(Opcode::SH, 17, 0, 0x43627530, false, true), + Instruction::new(Opcode::LW, 12, 0, 0x43627530, false, true), + Instruction::new(Opcode::SH, 17, 0, 0x43627532, false, true), + Instruction::new(Opcode::LW, 11, 0, 0x43627530, false, true), + ]; + Program::new(instructions, 0, 0) + } +} diff --git a/core/src/runtime/record.rs b/crates/core/executor/src/record.rs similarity index 52% rename from core/src/runtime/record.rs rename to crates/core/executor/src/record.rs index 2dfec4bd15..fe2fab16de 100644 --- a/core/src/runtime/record.rs +++ b/crates/core/executor/src/record.rs @@ -1,29 +1,19 @@ use hashbrown::HashMap; -use itertools::EitherOrBoth; -use itertools::Itertools; +use itertools::{EitherOrBoth, Itertools}; +use p3_field::AbstractField; +use sp1_stark::{air::PublicValues, MachineRecord, SP1CoreOpts, SplitOpts}; use std::sync::Arc; -use p3_field::AbstractField; use serde::{Deserialize, Serialize}; -use super::program::Program; -use super::Opcode; -use crate::air::PublicValues; -use crate::alu::AluEvent; -use crate::bytes::event::add_sharded_byte_lookup_events; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::cpu::CpuEvent; -use crate::runtime::MemoryInitializeFinalizeEvent; -use crate::runtime::MemoryRecordEnum; -use crate::stark::MachineRecord; -use crate::syscall::precompiles::edwards::EdDecompressEvent; -use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; -use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; -use crate::syscall::precompiles::uint256::Uint256MulEvent; -use crate::syscall::precompiles::ECDecompressEvent; -use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; -use crate::utils::SP1CoreOpts; +use super::{program::Program, Opcode}; +use crate::events::{ + add_sharded_byte_lookup_events, AluEvent, ByteLookupEvent, ByteRecord, CpuEvent, + EdDecompressEvent, EllipticCurveAddEvent, EllipticCurveDecompressEvent, + EllipticCurveDoubleEvent, Fp2AddSubEvent, Fp2MulEvent, FpOpEvent, KeccakPermuteEvent, + MemoryInitializeFinalizeEvent, MemoryRecordEnum, ShaCompressEvent, ShaExtendEvent, + Uint256MulEvent, +}; /// A record of the execution of a program. /// @@ -32,309 +22,96 @@ use crate::utils::SP1CoreOpts; pub struct ExecutionRecord { /// The program. pub program: Arc, - /// A trace of the CPU events which get emitted during execution. pub cpu_events: Vec, - /// A trace of the ADD, and ADDI events. pub add_events: Vec, - /// A trace of the MUL events. pub mul_events: Vec, - /// A trace of the SUB events. pub sub_events: Vec, - /// A trace of the XOR, XORI, OR, ORI, AND, and ANDI events. pub bitwise_events: Vec, - /// A trace of the SLL and SLLI events. pub shift_left_events: Vec, - /// A trace of the SRL, SRLI, SRA, and SRAI events. pub shift_right_events: Vec, - /// A trace of the DIV, DIVU, REM, and REMU events. pub divrem_events: Vec, - /// A trace of the SLT, SLTI, SLTU, and SLTIU events. pub lt_events: Vec, - - /// All byte lookups that are needed. - /// - /// The layout is shard -> (event -> count). Byte lookups are sharded to prevent the - /// multiplicities from overflowing. + /// A trace of the byte lookups that are needed. pub byte_lookups: HashMap>, - + /// A trace of the sha256 extend events. pub sha_extend_events: Vec, - + /// A trace of the sha256 compress events. pub sha_compress_events: Vec, - + /// A trace of the keccak256 permute events. pub keccak_permute_events: Vec, - - pub ed_add_events: Vec, - + /// A trace of the edwards add events. + pub ed_add_events: Vec, + /// A trace of the edwards decompress events. pub ed_decompress_events: Vec, - - pub secp256k1_add_events: Vec, - - pub secp256k1_double_events: Vec, - - pub bn254_add_events: Vec, - - pub bn254_double_events: Vec, - - pub k256_decompress_events: Vec, - - pub bls12381_add_events: Vec, - - pub bls12381_double_events: Vec, - + /// A trace of the secp256k1 add events. + pub secp256k1_add_events: Vec, + /// A trace of the secp256k1 double events. + pub secp256k1_double_events: Vec, + /// A trace of the bn254 add events. + pub bn254_add_events: Vec, + /// A trace of the bn254 double events. + pub bn254_double_events: Vec, + /// A trace of the k256 decompress events. + pub k256_decompress_events: Vec, + /// A trace of the bls12381 add events. + pub bls12381_add_events: Vec, + /// A trace of the bls12381 double events. + pub bls12381_double_events: Vec, + /// A trace of the uint256 mul events. pub uint256_mul_events: Vec, - + /// A trace of the memory initialize events. pub memory_initialize_events: Vec, - + /// A trace of the memory finalize events. pub memory_finalize_events: Vec, - - pub bls12381_decompress_events: Vec, - + /// A trace of the bls12381 decompress events. + pub bls12381_decompress_events: Vec, + /// A trace of the bls12381 fp events. + pub bls12381_fp_events: Vec, + /// A trace of the bls12381 fp2 add/sub events. + pub bls12381_fp2_addsub_events: Vec, + /// A trace of the bls12381 fp2 mul events. + pub bls12381_fp2_mul_events: Vec, + /// A trace of the bn254 fp events. + pub bn254_fp_events: Vec, + /// A trace of the bn254 fp2 add/sub events. + pub bn254_fp2_addsub_events: Vec, + /// A trace of the bn254 fp2 mul events. + pub bn254_fp2_mul_events: Vec, /// The public values. pub public_values: PublicValues, - + /// The nonce lookup. pub nonce_lookup: HashMap, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct SplitOpts { - pub deferred_shift_threshold: usize, - pub keccak_split_threshold: usize, - pub sha_extend_split_threshold: usize, - pub sha_compress_split_threshold: usize, - pub memory_split_threshold: usize, -} - -impl SplitOpts { - pub fn new(deferred_shift_threshold: usize) -> Self { - Self { - deferred_shift_threshold, - keccak_split_threshold: deferred_shift_threshold / 24, - sha_extend_split_threshold: deferred_shift_threshold / 48, - sha_compress_split_threshold: deferred_shift_threshold / 80, - memory_split_threshold: deferred_shift_threshold * 4, - } - } -} - -impl MachineRecord for ExecutionRecord { - type Config = SP1CoreOpts; - - fn stats(&self) -> HashMap { - let mut stats = HashMap::new(); - stats.insert("cpu_events".to_string(), self.cpu_events.len()); - stats.insert("add_events".to_string(), self.add_events.len()); - stats.insert("mul_events".to_string(), self.mul_events.len()); - stats.insert("sub_events".to_string(), self.sub_events.len()); - stats.insert("bitwise_events".to_string(), self.bitwise_events.len()); - stats.insert( - "shift_left_events".to_string(), - self.shift_left_events.len(), - ); - stats.insert( - "shift_right_events".to_string(), - self.shift_right_events.len(), - ); - stats.insert("divrem_events".to_string(), self.divrem_events.len()); - stats.insert("lt_events".to_string(), self.lt_events.len()); - stats.insert( - "sha_extend_events".to_string(), - self.sha_extend_events.len(), - ); - stats.insert( - "sha_compress_events".to_string(), - self.sha_compress_events.len(), - ); - stats.insert( - "keccak_permute_events".to_string(), - self.keccak_permute_events.len(), - ); - stats.insert("ed_add_events".to_string(), self.ed_add_events.len()); - stats.insert( - "ed_decompress_events".to_string(), - self.ed_decompress_events.len(), - ); - stats.insert( - "secp256k1_add_events".to_string(), - self.secp256k1_add_events.len(), - ); - stats.insert( - "secp256k1_double_events".to_string(), - self.secp256k1_double_events.len(), - ); - stats.insert("bn254_add_events".to_string(), self.bn254_add_events.len()); - stats.insert( - "bn254_double_events".to_string(), - self.bn254_double_events.len(), - ); - stats.insert( - "k256_decompress_events".to_string(), - self.k256_decompress_events.len(), - ); - stats.insert( - "bls12381_add_events".to_string(), - self.bls12381_add_events.len(), - ); - stats.insert( - "bls12381_double_events".to_string(), - self.bls12381_double_events.len(), - ); - stats.insert( - "uint256_mul_events".to_string(), - self.uint256_mul_events.len(), - ); - stats.insert( - "bls12381_decompress_events".to_string(), - self.bls12381_decompress_events.len(), - ); - stats.insert( - "memory_initialize_events".to_string(), - self.memory_initialize_events.len(), - ); - stats.insert( - "memory_finalize_events".to_string(), - self.memory_finalize_events.len(), - ); - if !self.cpu_events.is_empty() { - let shard = self.cpu_events[0].shard; - stats.insert( - "byte_lookups".to_string(), - self.byte_lookups.get(&shard).map_or(0, |v| v.len()), - ); - } - // Filter out the empty events. - stats.retain(|_, v| *v != 0); - stats - } - - fn append(&mut self, other: &mut ExecutionRecord) { - self.cpu_events.append(&mut other.cpu_events); - self.add_events.append(&mut other.add_events); - self.sub_events.append(&mut other.sub_events); - self.mul_events.append(&mut other.mul_events); - self.bitwise_events.append(&mut other.bitwise_events); - self.shift_left_events.append(&mut other.shift_left_events); - self.shift_right_events - .append(&mut other.shift_right_events); - self.divrem_events.append(&mut other.divrem_events); - self.lt_events.append(&mut other.lt_events); - self.sha_extend_events.append(&mut other.sha_extend_events); - self.sha_compress_events - .append(&mut other.sha_compress_events); - self.keccak_permute_events - .append(&mut other.keccak_permute_events); - self.ed_add_events.append(&mut other.ed_add_events); - self.ed_decompress_events - .append(&mut other.ed_decompress_events); - self.secp256k1_add_events - .append(&mut other.secp256k1_add_events); - self.secp256k1_double_events - .append(&mut other.secp256k1_double_events); - self.bn254_add_events.append(&mut other.bn254_add_events); - self.bn254_double_events - .append(&mut other.bn254_double_events); - self.k256_decompress_events - .append(&mut other.k256_decompress_events); - self.bls12381_add_events - .append(&mut other.bls12381_add_events); - self.bls12381_double_events - .append(&mut other.bls12381_double_events); - self.uint256_mul_events - .append(&mut other.uint256_mul_events); - self.bls12381_decompress_events - .append(&mut other.bls12381_decompress_events); - - if self.byte_lookups.is_empty() { - self.byte_lookups = std::mem::take(&mut other.byte_lookups); - } else { - self.add_sharded_byte_lookup_events(vec![&other.byte_lookups]); - } - - self.memory_initialize_events - .append(&mut other.memory_initialize_events); - self.memory_finalize_events - .append(&mut other.memory_finalize_events); - } - - fn register_nonces(&mut self, _opts: &Self::Config) { - self.add_events.iter().enumerate().for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.sub_events.iter().enumerate().for_each(|(i, event)| { - self.nonce_lookup - .insert(event.lookup_id, (self.add_events.len() + i) as u32); - }); - - self.mul_events.iter().enumerate().for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.bitwise_events - .iter() - .enumerate() - .for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.shift_left_events - .iter() - .enumerate() - .for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.shift_right_events - .iter() - .enumerate() - .for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.divrem_events - .iter() - .enumerate() - .for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - - self.lt_events.iter().enumerate().for_each(|(i, event)| { - self.nonce_lookup.insert(event.lookup_id, i as u32); - }); - } - - /// Retrieves the public values. This method is needed for the `MachineRecord` trait, since - fn public_values(&self) -> Vec { - self.public_values.to_vec() - } -} - impl ExecutionRecord { + /// Create a new [`ExecutionRecord`]. + #[must_use] pub fn new(program: Arc) -> Self { - Self { - program, - ..Default::default() - } + Self { program, ..Default::default() } } + /// Add a mul event to the execution record. pub fn add_mul_event(&mut self, mul_event: AluEvent) { self.mul_events.push(mul_event); } + /// Add a lt event to the execution record. pub fn add_lt_event(&mut self, lt_event: AluEvent) { self.lt_events.push(lt_event); } + /// Add a batch of alu events to the execution record. pub fn add_alu_events(&mut self, mut alu_events: HashMap>) { - for (opcode, value) in alu_events.iter_mut() { + for (opcode, value) in &mut alu_events { match opcode { Opcode::ADD => { self.add_events.append(value); @@ -358,21 +135,25 @@ impl ExecutionRecord { self.lt_events.append(value); } _ => { - panic!("Invalid opcode: {:?}", opcode); + panic!("Invalid opcode: {opcode:?}"); } } } } - /// Take out events from the [ExecutionRecord] that should be deferred to a separate shard. + /// Take out events from the [`ExecutionRecord`] that should be deferred to a separate shard. /// /// Note: we usually defer events that would increase the recursion cost significantly if /// included in every shard. + #[must_use] pub fn defer(&mut self) -> ExecutionRecord { ExecutionRecord { keccak_permute_events: std::mem::take(&mut self.keccak_permute_events), secp256k1_add_events: std::mem::take(&mut self.secp256k1_add_events), secp256k1_double_events: std::mem::take(&mut self.secp256k1_double_events), + bn254_fp_events: std::mem::take(&mut self.bn254_fp_events), + bn254_fp2_addsub_events: std::mem::take(&mut self.bn254_fp2_addsub_events), + bn254_fp2_mul_events: std::mem::take(&mut self.bn254_fp2_mul_events), bn254_add_events: std::mem::take(&mut self.bn254_add_events), bn254_double_events: std::mem::take(&mut self.bn254_double_events), bls12381_add_events: std::mem::take(&mut self.bls12381_add_events), @@ -383,6 +164,9 @@ impl ExecutionRecord { ed_decompress_events: std::mem::take(&mut self.ed_decompress_events), k256_decompress_events: std::mem::take(&mut self.k256_decompress_events), uint256_mul_events: std::mem::take(&mut self.uint256_mul_events), + bls12381_fp_events: std::mem::take(&mut self.bls12381_fp_events), + bls12381_fp2_addsub_events: std::mem::take(&mut self.bls12381_fp2_addsub_events), + bls12381_fp2_mul_events: std::mem::take(&mut self.bls12381_fp2_mul_events), bls12381_decompress_events: std::mem::take(&mut self.bls12381_decompress_events), memory_initialize_events: std::mem::take(&mut self.memory_initialize_events), memory_finalize_events: std::mem::take(&mut self.memory_finalize_events), @@ -390,8 +174,8 @@ impl ExecutionRecord { } } - /// Splits the deferred [ExecutionRecord] into multiple [ExecutionRecord]s, each which contain - /// a "reasonable" number of deferred events. + /// Splits the deferred [`ExecutionRecord`] into multiple [`ExecutionRecord`]s, each which + /// contain a "reasonable" number of deferred events. pub fn split(&mut self, last: bool, opts: SplitOpts) -> Vec { let mut shards = Vec::new(); @@ -422,122 +206,40 @@ impl ExecutionRecord { }; } - split_events!( - self, - keccak_permute_events, - shards, - opts.keccak_split_threshold, - last - ); - split_events!( - self, - secp256k1_add_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - secp256k1_double_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - bn254_add_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - bn254_double_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - bls12381_add_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - bls12381_double_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - sha_extend_events, - shards, - opts.sha_extend_split_threshold, - last - ); - split_events!( - self, - sha_compress_events, - shards, - opts.sha_compress_split_threshold, - last - ); - split_events!( - self, - ed_add_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - ed_decompress_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - k256_decompress_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - uint256_mul_events, - shards, - opts.deferred_shift_threshold, - last - ); - split_events!( - self, - bls12381_decompress_events, - shards, - opts.deferred_shift_threshold, - last - ); + split_events!(self, keccak_permute_events, shards, opts.keccak, last); + split_events!(self, secp256k1_add_events, shards, opts.deferred, last); + split_events!(self, secp256k1_double_events, shards, opts.deferred, last); + split_events!(self, bn254_add_events, shards, opts.deferred, last); + split_events!(self, bn254_double_events, shards, opts.deferred, last); + split_events!(self, bls12381_add_events, shards, opts.deferred, last); + split_events!(self, bls12381_double_events, shards, opts.deferred, last); + split_events!(self, sha_extend_events, shards, opts.sha_extend, last); + split_events!(self, sha_compress_events, shards, opts.sha_compress, last); + split_events!(self, ed_add_events, shards, opts.deferred, last); + split_events!(self, ed_decompress_events, shards, opts.deferred, last); + split_events!(self, k256_decompress_events, shards, opts.deferred, last); + split_events!(self, uint256_mul_events, shards, opts.deferred, last); + split_events!(self, bls12381_decompress_events, shards, opts.deferred, last); + split_events!(self, bls12381_fp_events, shards, opts.deferred, last); + split_events!(self, bls12381_fp2_addsub_events, shards, opts.deferred, last); + split_events!(self, bls12381_fp2_mul_events, shards, opts.deferred, last); + split_events!(self, bn254_fp_events, shards, opts.deferred, last); + split_events!(self, bn254_fp2_addsub_events, shards, opts.deferred, last); + split_events!(self, bn254_fp2_mul_events, shards, opts.deferred, last); // _ = last_pct; if last { // shards.push(last_shard); - self.memory_initialize_events - .sort_by_key(|event| event.addr); + self.memory_initialize_events.sort_by_key(|event| event.addr); self.memory_finalize_events.sort_by_key(|event| event.addr); let mut init_addr_bits = [0; 32]; let mut finalize_addr_bits = [0; 32]; for mem_chunks in self .memory_initialize_events - .chunks(opts.memory_split_threshold) - .zip_longest( - self.memory_finalize_events - .chunks(opts.memory_split_threshold), - ) + .chunks(opts.memory) + .zip_longest(self.memory_finalize_events.chunks(opts.memory)) { let (mem_init_chunk, mem_finalize_chunk) = match mem_chunks { EitherOrBoth::Both(mem_init_chunk, mem_finalize_chunk) => { @@ -548,9 +250,7 @@ impl ExecutionRecord { }; let mut shard = ExecutionRecord::default(); shard.program = self.program.clone(); - shard - .memory_initialize_events - .extend_from_slice(mem_init_chunk); + shard.memory_initialize_events.extend_from_slice(mem_init_chunk); shard.public_values.previous_init_addr_bits = init_addr_bits; if let Some(last_event) = mem_init_chunk.last() { let last_init_addr_bits = core::array::from_fn(|i| (last_event.addr >> i) & 1); @@ -558,9 +258,7 @@ impl ExecutionRecord { } shard.public_values.last_init_addr_bits = init_addr_bits; - shard - .memory_finalize_events - .extend_from_slice(mem_finalize_chunk); + shard.memory_finalize_events.extend_from_slice(mem_finalize_chunk); shard.public_values.previous_finalize_addr_bits = finalize_addr_bits; if let Some(last_event) = mem_finalize_chunk.last() { let last_finalize_addr_bits = @@ -577,14 +275,159 @@ impl ExecutionRecord { } } +/// A memory access record. +#[derive(Debug, Copy, Clone, Default)] +pub struct MemoryAccessRecord { + /// The memory access of the `a` register. + pub a: Option, + /// The memory access of the `b` register. + pub b: Option, + /// The memory access of the `c` register. + pub c: Option, + /// The memory access of the `memory` register. + pub memory: Option, +} + +impl MachineRecord for ExecutionRecord { + type Config = SP1CoreOpts; + + fn stats(&self) -> HashMap { + let mut stats = HashMap::new(); + stats.insert("cpu_events".to_string(), self.cpu_events.len()); + stats.insert("add_events".to_string(), self.add_events.len()); + stats.insert("mul_events".to_string(), self.mul_events.len()); + stats.insert("sub_events".to_string(), self.sub_events.len()); + stats.insert("bitwise_events".to_string(), self.bitwise_events.len()); + stats.insert("shift_left_events".to_string(), self.shift_left_events.len()); + stats.insert("shift_right_events".to_string(), self.shift_right_events.len()); + stats.insert("divrem_events".to_string(), self.divrem_events.len()); + stats.insert("lt_events".to_string(), self.lt_events.len()); + stats.insert("sha_extend_events".to_string(), self.sha_extend_events.len()); + stats.insert("sha_compress_events".to_string(), self.sha_compress_events.len()); + stats.insert("keccak_permute_events".to_string(), self.keccak_permute_events.len()); + stats.insert("ed_add_events".to_string(), self.ed_add_events.len()); + stats.insert("ed_decompress_events".to_string(), self.ed_decompress_events.len()); + stats.insert("secp256k1_add_events".to_string(), self.secp256k1_add_events.len()); + stats.insert("secp256k1_double_events".to_string(), self.secp256k1_double_events.len()); + stats.insert("bn254_add_events".to_string(), self.bn254_add_events.len()); + stats.insert("bn254_double_events".to_string(), self.bn254_double_events.len()); + stats.insert("k256_decompress_events".to_string(), self.k256_decompress_events.len()); + stats.insert("bls12381_add_events".to_string(), self.bls12381_add_events.len()); + stats.insert("bls12381_double_events".to_string(), self.bls12381_double_events.len()); + stats.insert("uint256_mul_events".to_string(), self.uint256_mul_events.len()); + stats.insert("bls12381_fp_event".to_string(), self.bls12381_fp_events.len()); + stats.insert( + "bls12381_fp2_addsub_events".to_string(), + self.bls12381_fp2_addsub_events.len(), + ); + stats.insert("bls12381_fp2_mul_events".to_string(), self.bls12381_fp2_mul_events.len()); + stats.insert("bn254_fp_events".to_string(), self.bn254_fp_events.len()); + stats.insert("bn254_fp2_addsub_events".to_string(), self.bn254_fp2_addsub_events.len()); + stats.insert("bn254_fp2_mul_events".to_string(), self.bn254_fp2_mul_events.len()); + stats.insert( + "bls12381_decompress_events".to_string(), + self.bls12381_decompress_events.len(), + ); + stats.insert("memory_initialize_events".to_string(), self.memory_initialize_events.len()); + stats.insert("memory_finalize_events".to_string(), self.memory_finalize_events.len()); + if !self.cpu_events.is_empty() { + let shard = self.cpu_events[0].shard; + stats.insert( + "byte_lookups".to_string(), + self.byte_lookups.get(&shard).map_or(0, hashbrown::HashMap::len), + ); + } + // Filter out the empty events. + stats.retain(|_, v| *v != 0); + stats + } + + fn append(&mut self, other: &mut ExecutionRecord) { + self.cpu_events.append(&mut other.cpu_events); + self.add_events.append(&mut other.add_events); + self.sub_events.append(&mut other.sub_events); + self.mul_events.append(&mut other.mul_events); + self.bitwise_events.append(&mut other.bitwise_events); + self.shift_left_events.append(&mut other.shift_left_events); + self.shift_right_events.append(&mut other.shift_right_events); + self.divrem_events.append(&mut other.divrem_events); + self.lt_events.append(&mut other.lt_events); + self.sha_extend_events.append(&mut other.sha_extend_events); + self.sha_compress_events.append(&mut other.sha_compress_events); + self.keccak_permute_events.append(&mut other.keccak_permute_events); + self.ed_add_events.append(&mut other.ed_add_events); + self.ed_decompress_events.append(&mut other.ed_decompress_events); + self.secp256k1_add_events.append(&mut other.secp256k1_add_events); + self.secp256k1_double_events.append(&mut other.secp256k1_double_events); + self.bn254_add_events.append(&mut other.bn254_add_events); + self.bn254_double_events.append(&mut other.bn254_double_events); + self.k256_decompress_events.append(&mut other.k256_decompress_events); + self.bls12381_add_events.append(&mut other.bls12381_add_events); + self.bls12381_double_events.append(&mut other.bls12381_double_events); + self.uint256_mul_events.append(&mut other.uint256_mul_events); + self.bls12381_fp_events.append(&mut other.bls12381_fp_events); + self.bls12381_fp2_addsub_events.append(&mut other.bls12381_fp2_addsub_events); + self.bls12381_fp2_mul_events.append(&mut other.bls12381_fp2_mul_events); + self.bn254_fp_events.append(&mut other.bn254_fp_events); + self.bn254_fp2_addsub_events.append(&mut other.bn254_fp2_addsub_events); + self.bn254_fp2_mul_events.append(&mut other.bn254_fp2_mul_events); + self.bls12381_decompress_events.append(&mut other.bls12381_decompress_events); + + self.bls12381_decompress_events.append(&mut other.bls12381_decompress_events); + + if self.byte_lookups.is_empty() { + self.byte_lookups = std::mem::take(&mut other.byte_lookups); + } else { + self.add_sharded_byte_lookup_events(vec![&other.byte_lookups]); + } + + self.memory_initialize_events.append(&mut other.memory_initialize_events); + self.memory_finalize_events.append(&mut other.memory_finalize_events); + } + + fn register_nonces(&mut self, _opts: &Self::Config) { + self.add_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.sub_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, (self.add_events.len() + i) as u32); + }); + + self.mul_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.bitwise_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.shift_left_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.shift_right_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.divrem_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + + self.lt_events.iter().enumerate().for_each(|(i, event)| { + self.nonce_lookup.insert(event.lookup_id, i as u32); + }); + } + + /// Retrieves the public values. This method is needed for the `MachineRecord` trait, since + fn public_values(&self) -> Vec { + self.public_values.to_vec() + } +} + impl ByteRecord for ExecutionRecord { fn add_byte_lookup_event(&mut self, blu_event: ByteLookupEvent) { - *self - .byte_lookups - .entry(blu_event.shard) - .or_default() - .entry(blu_event) - .or_insert(0) += 1 + *self.byte_lookups.entry(blu_event.shard).or_default().entry(blu_event).or_insert(0) += 1; } #[inline] @@ -595,14 +438,3 @@ impl ByteRecord for ExecutionRecord { add_sharded_byte_lookup_events(&mut self.byte_lookups, new_events); } } - -#[derive(Debug, Copy, Clone, Default)] -pub struct MemoryAccessRecord { - pub a: Option, - pub b: Option, - pub c: Option, - pub memory: Option, -} - -/// The threshold for splitting deferred events. -pub const DEFERRED_SPLIT_THRESHOLD: usize = 1 << 19; diff --git a/core/src/runtime/register.rs b/crates/core/executor/src/register.rs similarity index 71% rename from core/src/runtime/register.rs rename to crates/core/executor/src/register.rs index 7ab2aa4cd1..176ef1c951 100644 --- a/core/src/runtime/register.rs +++ b/crates/core/executor/src/register.rs @@ -1,42 +1,82 @@ +//! Registers for the SP1 zkVM. + /// A register stores a 32-bit value used by operations. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Register { + /// %x0 X0 = 0, + /// %x1 X1 = 1, + /// %x2 X2 = 2, + /// %x3 X3 = 3, + /// %x4 X4 = 4, + /// %x5 X5 = 5, + /// %x6 X6 = 6, + /// %x7 X7 = 7, + /// %x8 X8 = 8, + /// %x9 X9 = 9, + /// %x10 X10 = 10, + /// %x11 X11 = 11, + /// %x12 X12 = 12, + /// %x13 X13 = 13, + /// %x14 X14 = 14, + /// %x15 X15 = 15, + /// %x16 X16 = 16, + /// %x17 X17 = 17, + /// %x18 X18 = 18, + /// %x19 X19 = 19, + /// %x20 X20 = 20, + /// %x21 X21 = 21, + /// %x22 X22 = 22, + /// %x23 X23 = 23, + /// %x24 X24 = 24, + /// %x25 X25 = 25, + /// %x26 X26 = 26, + /// %x27 X27 = 27, + /// %x28 X28 = 28, + /// %x29 X29 = 29, + /// %x30 X30 = 30, + /// %x31 X31 = 31, } impl Register { - #[inline(always)] + /// Create a new register from a u32. + /// + /// # Panics + /// + /// This function will panic if the register is invalid. + #[inline] + #[must_use] pub fn from_u32(value: u32) -> Self { match value { 0 => Register::X0, @@ -71,7 +111,7 @@ impl Register { 29 => Register::X29, 30 => Register::X30, 31 => Register::X31, - _ => panic!("invalid register {}", value), + _ => panic!("invalid register {value}"), } } } diff --git a/crates/core/executor/src/report.rs b/crates/core/executor/src/report.rs new file mode 100644 index 0000000000..3e4b29458a --- /dev/null +++ b/crates/core/executor/src/report.rs @@ -0,0 +1,83 @@ +use std::{ + collections::{hash_map::Entry, HashMap}, + fmt::{Display, Formatter, Result as FmtResult}, + hash::Hash, + ops::{Add, AddAssign}, +}; + +use crate::{events::sorted_table_lines, syscalls::SyscallCode, Opcode}; + +/// An execution report. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct ExecutionReport { + /// The opcode counts. + pub opcode_counts: HashMap, + /// The syscall counts. + pub syscall_counts: HashMap, + /// The cycle tracker counts. + pub cycle_tracker: HashMap, + /// The unique memory address counts. + pub touched_memory_addresses: u64, +} + +impl ExecutionReport { + /// Compute the total number of instructions run during the execution. + #[must_use] + pub fn total_instruction_count(&self) -> u64 { + self.opcode_counts.values().sum() + } + + /// Compute the total number of syscalls made during the execution. + #[must_use] + pub fn total_syscall_count(&self) -> u64 { + self.syscall_counts.values().sum() + } +} + +/// Combines two `HashMap`s together. If a key is in both maps, the values are added together. +fn hashmap_add_assign(lhs: &mut HashMap, rhs: HashMap) +where + K: Eq + Hash, + V: AddAssign, +{ + for (k, v) in rhs { + // Can't use `.and_modify(...).or_insert(...)` because we want to use `v` in both places. + match lhs.entry(k) { + Entry::Occupied(e) => *e.into_mut() += v, + Entry::Vacant(e) => drop(e.insert(v)), + } + } +} + +impl AddAssign for ExecutionReport { + fn add_assign(&mut self, rhs: Self) { + hashmap_add_assign(&mut self.opcode_counts, rhs.opcode_counts); + hashmap_add_assign(&mut self.syscall_counts, rhs.syscall_counts); + self.touched_memory_addresses += rhs.touched_memory_addresses; + } +} + +impl Add for ExecutionReport { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self::Output { + self += rhs; + self + } +} + +impl Display for ExecutionReport { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + writeln!(f, "opcode counts ({} total instructions):", self.total_instruction_count())?; + for line in sorted_table_lines(&self.opcode_counts) { + writeln!(f, " {line}")?; + } + + writeln!(f, "syscall counts ({} total syscall instructions):", self.total_syscall_count())?; + for line in sorted_table_lines(&self.syscall_counts) { + writeln!(f, " {line}")?; + } + + Ok(()) + } +} diff --git a/core/src/runtime/state.rs b/crates/core/executor/src/state.rs similarity index 69% rename from core/src/runtime/state.rs rename to crates/core/executor/src/state.rs index 0368fe4718..be43718250 100644 --- a/core/src/runtime/state.rs +++ b/crates/core/executor/src/state.rs @@ -1,18 +1,19 @@ use std::{ - collections::HashMap, fs::File, io::{Seek, Write}, }; +use hashbrown::HashMap; use nohash_hasher::BuildNoHashHasher; use serde::{Deserialize, Serialize}; use serde_with::serde_as; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, ShardProof, StarkVerifyingKey}; -use super::{ExecutionRecord, MemoryAccessRecord, MemoryRecord, SyscallCode}; -use crate::utils::{deserialize_hashmap_as_vec, serialize_hashmap_as_vec}; use crate::{ - stark::{ShardProof, StarkVerifyingKey}, - utils::BabyBearPoseidon2, + events::MemoryRecord, + record::{ExecutionRecord, MemoryAccessRecord}, + syscalls::SyscallCode, + ExecutorMode, }; /// Holds data describing the current state of a program's execution. @@ -38,18 +39,18 @@ pub struct ExecutionState { /// The memory which instructions operate over. Values contain the memory value and last shard /// + timestamp that each memory address was accessed. - #[serde( - serialize_with = "serialize_hashmap_as_vec", - deserialize_with = "deserialize_hashmap_as_vec" - )] + // #[serde( + // serialize_with = "serialize_hashmap_as_vec", + // deserialize_with = "deserialize_hashmap_as_vec" + // )] pub memory: HashMap>, /// Uninitialized memory addresses that have a specific value they should be initialized with. /// SyscallHintRead uses this to write hint data into uninitialized memory. - #[serde( - serialize_with = "serialize_hashmap_as_vec", - deserialize_with = "deserialize_hashmap_as_vec" - )] + // #[serde( + // serialize_with = "serialize_hashmap_as_vec", + // deserialize_with = "deserialize_hashmap_as_vec" + // )] pub uninitialized_memory: HashMap>, /// A stream of input values (global to the entire program). @@ -59,10 +60,7 @@ pub struct ExecutionState { pub input_stream_ptr: usize, /// A stream of proofs inputted to the program. - pub proof_stream: Vec<( - ShardProof, - StarkVerifyingKey, - )>, + pub proof_stream: Vec<(ShardProof, StarkVerifyingKey)>, /// A ptr to the current position in the proof stream, incremented after verifying a proof. pub proof_stream_ptr: usize, @@ -70,7 +68,8 @@ pub struct ExecutionState { /// A stream of public values from the program (global to entire program). pub public_values_stream: Vec, - /// A ptr to the current position in the public values stream, incremented when reading from public_values_stream. + /// A ptr to the current position in the public values stream, incremented when reading from + /// public_values_stream. pub public_values_stream_ptr: usize, /// Keeps track of how many times a certain syscall has been called. @@ -78,6 +77,8 @@ pub struct ExecutionState { } impl ExecutionState { + #[must_use] + /// Create a new [`ExecutionState`]. pub fn new(pc_start: u32) -> Self { Self { global_clk: 0, @@ -101,30 +102,26 @@ impl ExecutionState { /// Holds data to track changes made to the runtime since a fork point. #[derive(Debug, Clone, Default)] -pub(crate) struct ForkState { - /// Original global_clk - pub(crate) global_clk: u64, - - /// Original clk - pub(crate) clk: u32, - - /// Original program counter - pub(crate) pc: u32, - - /// Only contains the original memory values for addresses that have been modified - pub(crate) memory_diff: HashMap, BuildNoHashHasher>, - - /// Full record from original state - pub(crate) op_record: MemoryAccessRecord, - - /// Full shard from original state - pub(crate) record: ExecutionRecord, - - // Emit events from original state - pub(crate) emit_events: bool, +#[allow(dead_code)] +pub struct ForkState { + /// The `global_clk` value at the fork point. + pub global_clk: u64, + /// The original `clk` value at the fork point. + pub clk: u32, + /// The original `pc` value at the fork point. + pub pc: u32, + /// All memory changes since the fork point. + pub memory_diff: HashMap, BuildNoHashHasher>, + /// The original memory access record at the fork point. + pub op_record: MemoryAccessRecord, + /// The original execution record at the fork point. + pub record: ExecutionRecord, + /// Whether `emit_events` was enabled at the fork point. + pub executor_mode: ExecutorMode, } impl ExecutionState { + /// Save the execution state to a file. pub fn save(&self, file: &mut File) -> std::io::Result<()> { let mut writer = std::io::BufWriter::new(file); bincode::serialize_into(&mut writer, self).unwrap(); diff --git a/core/src/runtime/subproof.rs b/crates/core/executor/src/subproof.rs similarity index 82% rename from core/src/runtime/subproof.rs rename to crates/core/executor/src/subproof.rs index 701608646d..09d7c57a77 100644 --- a/core/src/runtime/subproof.rs +++ b/crates/core/executor/src/subproof.rs @@ -1,8 +1,9 @@ +//! Types and methods for subproof verification inside the [`crate::Executor`]. + use std::sync::atomic::AtomicBool; -use crate::{ - stark::{MachineVerificationError, ShardProof, StarkVerifyingKey}, - utils::BabyBearPoseidon2, +use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, MachineVerificationError, ShardProof, StarkVerifyingKey, }; /// Verifier used in runtime when `sp1_zkvm::precompiles::verify::verify_sp1_proof` is called. This @@ -12,6 +13,7 @@ use crate::{ /// This needs to be passed in rather than written directly since the actual implementation relies /// on crates in recursion that depend on sp1-core. pub trait SubproofVerifier: Sync + Send { + /// Verify a deferred proof. fn verify_deferred_proof( &self, proof: &ShardProof, @@ -28,10 +30,10 @@ pub struct DefaultSubproofVerifier { } impl DefaultSubproofVerifier { + /// Creates a new [`DefaultSubproofVerifier`]. + #[must_use] pub fn new() -> Self { - Self { - printed: AtomicBool::new(false), - } + Self { printed: AtomicBool::new(false) } } } @@ -45,8 +47,7 @@ impl SubproofVerifier for DefaultSubproofVerifier { ) -> Result<(), MachineVerificationError> { if !self.printed.load(std::sync::atomic::Ordering::SeqCst) { tracing::info!("Not verifying sub proof during runtime"); - self.printed - .store(true, std::sync::atomic::Ordering::SeqCst); + self.printed.store(true, std::sync::atomic::Ordering::SeqCst); } Ok(()) } diff --git a/crates/core/executor/src/syscalls/code.rs b/crates/core/executor/src/syscalls/code.rs new file mode 100644 index 0000000000..929d7003c2 --- /dev/null +++ b/crates/core/executor/src/syscalls/code.rs @@ -0,0 +1,214 @@ +use serde::{Deserialize, Serialize}; +use strum_macros::EnumIter; + +/// System Calls. +/// +/// A system call is invoked by the the `ecall` instruction with a specific value in register t0. +/// The syscall number is a 32-bit integer with the following little-endian layout: +/// +/// | Byte 0 | Byte 1 | Byte 2 | Byte 3 | +/// | ------ | ------ | ------ | ------ | +/// | ID | Table | Cycles | Unused | +/// +/// where: +/// - Byte 0: The system call identifier. +/// - Byte 1: Whether the handler of the system call has its own table. This is used in the CPU +/// table to determine whether to lookup the syscall using the syscall interaction. +/// - Byte 2: The number of additional cycles the syscall uses. This is used to make sure the # of +/// memory accesses is bounded. +/// - Byte 3: Currently unused. +#[derive( + Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter, Ord, PartialOrd, Serialize, Deserialize, +)] +#[allow(non_camel_case_types)] +#[allow(clippy::upper_case_acronyms)] +pub enum SyscallCode { + /// Halts the program. + HALT = 0x00_00_00_00, + + /// Write to the output buffer. + WRITE = 0x00_00_00_02, + + /// Enter unconstrained block. + ENTER_UNCONSTRAINED = 0x00_00_00_03, + + /// Exit unconstrained block. + EXIT_UNCONSTRAINED = 0x00_00_00_04, + + /// Executes the `SHA_EXTEND` precompile. + SHA_EXTEND = 0x00_30_01_05, + + /// Executes the `SHA_COMPRESS` precompile. + SHA_COMPRESS = 0x00_01_01_06, + + /// Executes the `ED_ADD` precompile. + ED_ADD = 0x00_01_01_07, + + /// Executes the `ED_DECOMPRESS` precompile. + ED_DECOMPRESS = 0x00_00_01_08, + + /// Executes the `KECCAK_PERMUTE` precompile. + KECCAK_PERMUTE = 0x00_01_01_09, + + /// Executes the `SECP256K1_ADD` precompile. + SECP256K1_ADD = 0x00_01_01_0A, + + /// Executes the `SECP256K1_DOUBLE` precompile. + SECP256K1_DOUBLE = 0x00_00_01_0B, + + /// Executes the `SECP256K1_DECOMPRESS` precompile. + SECP256K1_DECOMPRESS = 0x00_00_01_0C, + + /// Executes the `BN254_ADD` precompile. + BN254_ADD = 0x00_01_01_0E, + + /// Executes the `BN254_DOUBLE` precompile. + BN254_DOUBLE = 0x00_00_01_0F, + + /// Executes the `COMMIT` precompile. + COMMIT = 0x00_00_00_10, + + /// Executes the `COMMIT_DEFERRED_PROOFS` precompile. + COMMIT_DEFERRED_PROOFS = 0x00_00_00_1A, + + /// Executes the `VERIFY_SP1_PROOF` precompile. + VERIFY_SP1_PROOF = 0x00_00_00_1B, + + /// Executes the `BLS12381_DECOMPRESS` precompile. + BLS12381_DECOMPRESS = 0x00_00_01_1C, + + /// Executes the `HINT_LEN` precompile. + HINT_LEN = 0x00_00_00_F0, + + /// Executes the `HINT_READ` precompile. + HINT_READ = 0x00_00_00_F1, + + /// Executes the `UINT256_MUL` precompile. + UINT256_MUL = 0x00_01_01_1D, + + /// Executes the `BLS12381_ADD` precompile. + BLS12381_ADD = 0x00_01_01_1E, + + /// Executes the `BLS12381_DOUBLE` precompile. + BLS12381_DOUBLE = 0x00_00_01_1F, + + /// Executes the `BLS12381_FP_ADD` precompile. + BLS12381_FP_ADD = 0x00_01_01_20, + + /// Executes the `BLS12381_FP_SUB` precompile. + BLS12381_FP_SUB = 0x00_01_01_21, + + /// Executes the `BLS12381_FP_MUL` precompile. + BLS12381_FP_MUL = 0x00_01_01_22, + + /// Executes the `BLS12381_FP2_ADD` precompile. + BLS12381_FP2_ADD = 0x00_01_01_23, + + /// Executes the `BLS12381_FP2_SUB` precompile. + BLS12381_FP2_SUB = 0x00_01_01_24, + + /// Executes the `BLS12381_FP2_MUL` precompile. + BLS12381_FP2_MUL = 0x00_01_01_25, + + /// Executes the `BN254_FP_ADD` precompile. + BN254_FP_ADD = 0x00_01_01_26, + + /// Executes the `BN254_FP_SUB` precompile. + BN254_FP_SUB = 0x00_01_01_27, + + /// Executes the `BN254_FP_MUL` precompile. + BN254_FP_MUL = 0x00_01_01_28, + + /// Executes the `BN254_FP2_ADD` precompile. + BN254_FP2_ADD = 0x00_01_01_29, + + /// Executes the `BN254_FP2_SUB` precompile. + BN254_FP2_SUB = 0x00_01_01_2A, + + /// Executes the `BN254_FP2_MUL` precompile. + BN254_FP2_MUL = 0x00_01_01_2B, +} + +impl SyscallCode { + /// Create a [`SyscallCode`] from a u32. + #[must_use] + pub fn from_u32(value: u32) -> Self { + match value { + 0x00_00_00_00 => SyscallCode::HALT, + 0x00_00_00_02 => SyscallCode::WRITE, + 0x00_00_00_03 => SyscallCode::ENTER_UNCONSTRAINED, + 0x00_00_00_04 => SyscallCode::EXIT_UNCONSTRAINED, + 0x00_30_01_05 => SyscallCode::SHA_EXTEND, + 0x00_01_01_06 => SyscallCode::SHA_COMPRESS, + 0x00_01_01_07 => SyscallCode::ED_ADD, + 0x00_00_01_08 => SyscallCode::ED_DECOMPRESS, + 0x00_01_01_09 => SyscallCode::KECCAK_PERMUTE, + 0x00_01_01_0A => SyscallCode::SECP256K1_ADD, + 0x00_00_01_0B => SyscallCode::SECP256K1_DOUBLE, + 0x00_00_01_0C => SyscallCode::SECP256K1_DECOMPRESS, + 0x00_01_01_0E => SyscallCode::BN254_ADD, + 0x00_00_01_0F => SyscallCode::BN254_DOUBLE, + 0x00_01_01_1E => SyscallCode::BLS12381_ADD, + 0x00_00_01_1F => SyscallCode::BLS12381_DOUBLE, + 0x00_00_00_10 => SyscallCode::COMMIT, + 0x00_00_00_1A => SyscallCode::COMMIT_DEFERRED_PROOFS, + 0x00_00_00_1B => SyscallCode::VERIFY_SP1_PROOF, + 0x00_00_00_F0 => SyscallCode::HINT_LEN, + 0x00_00_00_F1 => SyscallCode::HINT_READ, + 0x00_01_01_1D => SyscallCode::UINT256_MUL, + 0x00_01_01_20 => SyscallCode::BLS12381_FP_ADD, + 0x00_01_01_21 => SyscallCode::BLS12381_FP_SUB, + 0x00_01_01_22 => SyscallCode::BLS12381_FP_MUL, + 0x00_01_01_23 => SyscallCode::BLS12381_FP2_ADD, + 0x00_01_01_24 => SyscallCode::BLS12381_FP2_SUB, + 0x00_01_01_25 => SyscallCode::BLS12381_FP2_MUL, + 0x00_01_01_26 => SyscallCode::BN254_FP_ADD, + 0x00_01_01_27 => SyscallCode::BN254_FP_SUB, + 0x00_01_01_28 => SyscallCode::BN254_FP_MUL, + 0x00_01_01_29 => SyscallCode::BN254_FP2_ADD, + 0x00_01_01_2A => SyscallCode::BN254_FP2_SUB, + 0x00_01_01_2B => SyscallCode::BN254_FP2_MUL, + 0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS, + _ => panic!("invalid syscall number: {value}"), + } + } + + /// Get the system call identifier. + #[must_use] + pub fn syscall_id(self) -> u32 { + (self as u32).to_le_bytes()[0].into() + } + + /// Get whether the handler of the system call has its own table. + #[must_use] + pub fn should_send(self) -> u32 { + (self as u32).to_le_bytes()[1].into() + } + + /// Get the number of additional cycles the syscall uses. + #[must_use] + pub fn num_cycles(self) -> u32 { + (self as u32).to_le_bytes()[2].into() + } + + /// Map a syscall to another one in order to coalesce their counts. + #[must_use] + #[allow(clippy::match_same_arms)] + pub fn count_map(&self) -> Self { + match self { + SyscallCode::BN254_FP_SUB => SyscallCode::BN254_FP_ADD, + SyscallCode::BN254_FP_MUL => SyscallCode::BN254_FP_ADD, + SyscallCode::BN254_FP2_SUB => SyscallCode::BN254_FP2_ADD, + SyscallCode::BLS12381_FP_SUB => SyscallCode::BLS12381_FP_ADD, + SyscallCode::BLS12381_FP_MUL => SyscallCode::BLS12381_FP_ADD, + SyscallCode::BLS12381_FP2_SUB => SyscallCode::BLS12381_FP2_ADD, + _ => *self, + } + } +} + +impl std::fmt::Display for SyscallCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} diff --git a/crates/core/executor/src/syscalls/commit.rs b/crates/core/executor/src/syscalls/commit.rs new file mode 100644 index 0000000000..89c462a3d4 --- /dev/null +++ b/crates/core/executor/src/syscalls/commit.rs @@ -0,0 +1,20 @@ +use super::{Syscall, SyscallContext}; + +pub(crate) struct CommitSyscall; + +impl Syscall for CommitSyscall { + #[allow(clippy::mut_mut)] + fn execute( + &self, + ctx: &mut SyscallContext, + word_idx: u32, + public_values_digest_word: u32, + ) -> Option { + let rt = &mut ctx.rt; + + rt.record.public_values.committed_value_digest[word_idx as usize] = + public_values_digest_word; + + None + } +} diff --git a/crates/core/executor/src/syscalls/context.rs b/crates/core/executor/src/syscalls/context.rs new file mode 100644 index 0000000000..3d9716bb4b --- /dev/null +++ b/crates/core/executor/src/syscalls/context.rs @@ -0,0 +1,128 @@ +use crate::{ + events::{MemoryReadRecord, MemoryWriteRecord}, + record::ExecutionRecord, + Executor, Register, +}; + +/// A runtime for syscalls that is protected so that developers cannot arbitrarily modify the +/// runtime. +#[allow(dead_code)] +pub struct SyscallContext<'a, 'b: 'a> { + /// The current shard. + pub current_shard: u32, + /// The clock cycle. + pub clk: u32, + /// The next program counter. + pub next_pc: u32, + /// The exit code. + pub exit_code: u32, + /// The runtime. + pub rt: &'a mut Executor<'b>, + /// The syscall lookup id. + pub syscall_lookup_id: u128, +} + +impl<'a, 'b> SyscallContext<'a, 'b> { + /// Create a new [`SyscallContext`]. + pub fn new(runtime: &'a mut Executor<'b>) -> Self { + let current_shard = runtime.shard(); + let clk = runtime.state.clk; + Self { + current_shard, + clk, + next_pc: runtime.state.pc.wrapping_add(4), + exit_code: 0, + rt: runtime, + syscall_lookup_id: 0, + } + } + + /// Get a mutable reference to the execution record. + pub fn record_mut(&mut self) -> &mut ExecutionRecord { + &mut self.rt.record + } + + /// Get the current shard. + #[must_use] + pub fn current_shard(&self) -> u32 { + self.rt.state.current_shard + } + + /// Get the current channel. + #[must_use] + pub fn current_channel(&self) -> u8 { + self.rt.state.channel + } + + /// Read a word from memory. + pub fn mr(&mut self, addr: u32) -> (MemoryReadRecord, u32) { + let record = self.rt.mr(addr, self.current_shard, self.clk); + (record, record.value) + } + + /// Read a slice of words from memory. + pub fn mr_slice(&mut self, addr: u32, len: usize) -> (Vec, Vec) { + let mut records = Vec::new(); + let mut values = Vec::new(); + for i in 0..len { + let (record, value) = self.mr(addr + i as u32 * 4); + records.push(record); + values.push(value); + } + (records, values) + } + + /// Write a word to memory. + pub fn mw(&mut self, addr: u32, value: u32) -> MemoryWriteRecord { + self.rt.mw(addr, value, self.current_shard, self.clk) + } + + /// Write a slice of words to memory. + pub fn mw_slice(&mut self, addr: u32, values: &[u32]) -> Vec { + let mut records = Vec::new(); + for i in 0..values.len() { + let record = self.mw(addr + i as u32 * 4, values[i]); + records.push(record); + } + records + } + + /// Get the current value of a register, but doesn't use a memory record. + /// This is generally unconstrained, so you must be careful using it. + #[must_use] + pub fn register_unsafe(&mut self, register: Register) -> u32 { + self.rt.register(register) + } + + /// Get the current value of a byte, but doesn't use a memory record. + #[must_use] + pub fn byte_unsafe(&mut self, addr: u32) -> u8 { + self.rt.byte(addr) + } + + /// Get the current value of a word, but doesn't use a memory record. + #[must_use] + pub fn word_unsafe(&mut self, addr: u32) -> u32 { + self.rt.word(addr) + } + + /// Get a slice of words, but doesn't use a memory record. + #[must_use] + pub fn slice_unsafe(&mut self, addr: u32, len: usize) -> Vec { + let mut values = Vec::new(); + for i in 0..len { + values.push(self.rt.word(addr + i as u32 * 4)); + } + values + } + + /// Set the next program counter. + pub fn set_next_pc(&mut self, next_pc: u32) { + self.next_pc = next_pc; + } + + /// Set the exit code. + pub fn set_exit_code(&mut self, exit_code: u32) { + self.exit_code = exit_code; + } +} diff --git a/crates/core/executor/src/syscalls/deferred.rs b/crates/core/executor/src/syscalls/deferred.rs new file mode 100644 index 0000000000..d8f5167f58 --- /dev/null +++ b/crates/core/executor/src/syscalls/deferred.rs @@ -0,0 +1,14 @@ +use super::{Syscall, SyscallContext}; + +pub(crate) struct CommitDeferredSyscall; + +impl Syscall for CommitDeferredSyscall { + #[allow(clippy::mut_mut)] + fn execute(&self, ctx: &mut SyscallContext, word_idx: u32, word: u32) -> Option { + let rt = &mut ctx.rt; + + rt.record.public_values.deferred_proofs_digest[word_idx as usize] = word; + + None + } +} diff --git a/core/src/syscall/halt.rs b/crates/core/executor/src/syscalls/halt.rs similarity index 50% rename from core/src/syscall/halt.rs rename to crates/core/executor/src/syscalls/halt.rs index 8da62614db..5488be00e3 100644 --- a/core/src/syscall/halt.rs +++ b/crates/core/executor/src/syscalls/halt.rs @@ -1,14 +1,8 @@ -use crate::runtime::{Syscall, SyscallContext}; +use super::{context::SyscallContext, Syscall}; -pub struct SyscallHalt; +pub(crate) struct HaltSyscall; -impl SyscallHalt { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallHalt { +impl Syscall for HaltSyscall { fn execute(&self, ctx: &mut SyscallContext, exit_code: u32, _: u32) -> Option { ctx.set_next_pc(0); ctx.set_exit_code(exit_code); diff --git a/core/src/syscall/hint.rs b/crates/core/executor/src/syscalls/hint.rs similarity index 58% rename from core/src/syscall/hint.rs rename to crates/core/executor/src/syscalls/hint.rs index 27d89b396b..8f0b7f0b92 100644 --- a/core/src/syscall/hint.rs +++ b/crates/core/executor/src/syscalls/hint.rs @@ -1,15 +1,8 @@ -use crate::runtime::{Syscall, SyscallContext}; +use super::{Syscall, SyscallContext}; -pub struct SyscallHintLen; +pub(crate) struct HintLenSyscall; -/// SyscallHintLen returns the length of the next slice in the hint input stream. -impl SyscallHintLen { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallHintLen { +impl Syscall for HintLenSyscall { fn execute(&self, ctx: &mut SyscallContext, _arg1: u32, _arg2: u32) -> Option { if ctx.rt.state.input_stream_ptr >= ctx.rt.state.input_stream.len() { panic!( @@ -22,16 +15,9 @@ impl Syscall for SyscallHintLen { } } -pub struct SyscallHintRead; - -/// SyscallHintRead returns the length of the next slice in the hint input stream. -impl SyscallHintRead { - pub const fn new() -> Self { - Self - } -} +pub(crate) struct HintReadSyscall; -impl Syscall for SyscallHintRead { +impl Syscall for HintReadSyscall { fn execute(&self, ctx: &mut SyscallContext, ptr: u32, len: u32) -> Option { if ctx.rt.state.input_stream_ptr >= ctx.rt.state.input_stream.len() { panic!( @@ -42,15 +28,8 @@ impl Syscall for SyscallHintRead { } let vec = &ctx.rt.state.input_stream[ctx.rt.state.input_stream_ptr]; ctx.rt.state.input_stream_ptr += 1; - assert!( - !ctx.rt.unconstrained, - "hint read should not be used in a unconstrained block" - ); - assert_eq!( - vec.len() as u32, - len, - "hint input stream read length mismatch" - ); + assert!(!ctx.rt.unconstrained, "hint read should not be used in a unconstrained block"); + assert_eq!(vec.len() as u32, len, "hint input stream read length mismatch"); assert_eq!(ptr % 4, 0, "hint read address not aligned to 4 bytes"); // Iterate through the vec in 4-byte chunks for i in (0..len).step_by(4) { @@ -75,36 +54,3 @@ impl Syscall for SyscallHintRead { None } } - -#[cfg(test)] -mod tests { - use rand::RngCore; - - use crate::{ - io::SP1Stdin, - runtime::Program, - stark::CpuProver, - utils::{prove, setup_logger, BabyBearPoseidon2, SP1CoreOpts}, - }; - - const HINT_IO_ELF: &[u8] = - include_bytes!("../../../tests/hint-io/elf/riscv32im-succinct-zkvm-elf"); - - #[test] - fn test_hint_io() { - setup_logger(); - - let mut rng = rand::thread_rng(); - let mut data = vec![0u8; 1021]; - rng.fill_bytes(&mut data); - - let mut stdin = SP1Stdin::new(); - stdin.write(&data); - stdin.write_vec(data); - - let program = Program::from(HINT_IO_ELF); - - let config = BabyBearPoseidon2::new(); - prove::<_, CpuProver<_, _>>(program, &stdin, config, SP1CoreOpts::default()).unwrap(); - } -} diff --git a/crates/core/executor/src/syscalls/mod.rs b/crates/core/executor/src/syscalls/mod.rs new file mode 100644 index 0000000000..e4286bdaab --- /dev/null +++ b/crates/core/executor/src/syscalls/mod.rs @@ -0,0 +1,203 @@ +//! Syscall definitions & implementations for the [`crate::Executor`]. + +mod code; +mod commit; +mod context; +mod deferred; +mod halt; +mod hint; +mod precompiles; +mod unconstrained; +mod verify; +mod write; + +use std::sync::Arc; + +use commit::CommitSyscall; +use deferred::CommitDeferredSyscall; +use halt::HaltSyscall; +use hashbrown::HashMap; + +pub use code::*; +pub use context::*; +use hint::{HintLenSyscall, HintReadSyscall}; +use precompiles::{ + edwards::{add::EdwardsAddAssignSyscall, decompress::EdwardsDecompressSyscall}, + fptower::{Fp2AddSubSyscall, Fp2MulSyscall, FpOpSyscall}, + keccak256::permute::Keccak256PermuteSyscall, + sha256::{compress::Sha256CompressSyscall, extend::Sha256ExtendSyscall}, + uint256::Uint256MulSyscall, + weierstrass::{ + add::WeierstrassAddAssignSyscall, decompress::WeierstrassDecompressSyscall, + double::WeierstrassDoubleAssignSyscall, + }, +}; + +use sp1_curves::{ + edwards::ed25519::{Ed25519, Ed25519Parameters}, + weierstrass::{ + bls12_381::{Bls12381, Bls12381BaseField}, + bn254::{Bn254, Bn254BaseField}, + secp256k1::Secp256k1, + }, +}; +use unconstrained::{EnterUnconstrainedSyscall, ExitUnconstrainedSyscall}; +use verify::VerifySyscall; +use write::WriteSyscall; + +use crate::events::FieldOperation; + +/// A system call in the SP1 RISC-V zkVM. +/// +/// This trait implements methods needed to execute a system call inside the [`crate::Executor`]. +pub trait Syscall: Send + Sync { + /// Executes the syscall. + /// + /// Returns the resulting value of register a0. `arg1` and `arg2` are the values in registers + /// X10 and X11, respectively. While not a hard requirement, the convention is that the return + /// value is only for system calls such as `HALT`. Most precompiles use `arg1` and `arg2` to + /// denote the addresses of the input data, and write the result to the memory at `arg1`. + fn execute(&self, ctx: &mut SyscallContext, arg1: u32, arg2: u32) -> Option; + + /// The number of extra cycles that the syscall takes to execute. + /// + /// Unless this syscall is complex and requires many cycles, this should be zero. + fn num_extra_cycles(&self) -> u32 { + 0 + } +} + +/// Creates the default syscall map. +#[must_use] +pub fn default_syscall_map() -> HashMap> { + let mut syscall_map = HashMap::>::default(); + + syscall_map.insert(SyscallCode::HALT, Arc::new(HaltSyscall)); + + syscall_map.insert(SyscallCode::SHA_EXTEND, Arc::new(Sha256ExtendSyscall)); + + syscall_map.insert(SyscallCode::SHA_COMPRESS, Arc::new(Sha256CompressSyscall)); + + syscall_map.insert(SyscallCode::ED_ADD, Arc::new(EdwardsAddAssignSyscall::::new())); + + syscall_map.insert( + SyscallCode::ED_DECOMPRESS, + Arc::new(EdwardsDecompressSyscall::::new()), + ); + + syscall_map.insert(SyscallCode::KECCAK_PERMUTE, Arc::new(Keccak256PermuteSyscall)); + + syscall_map.insert( + SyscallCode::SECP256K1_ADD, + Arc::new(WeierstrassAddAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::SECP256K1_DOUBLE, + Arc::new(WeierstrassDoubleAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::SECP256K1_DECOMPRESS, + Arc::new(WeierstrassDecompressSyscall::::new()), + ); + + syscall_map + .insert(SyscallCode::BN254_ADD, Arc::new(WeierstrassAddAssignSyscall::::new())); + + syscall_map.insert( + SyscallCode::BN254_DOUBLE, + Arc::new(WeierstrassDoubleAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::BLS12381_ADD, + Arc::new(WeierstrassAddAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::BLS12381_DOUBLE, + Arc::new(WeierstrassDoubleAssignSyscall::::new()), + ); + + syscall_map.insert(SyscallCode::UINT256_MUL, Arc::new(Uint256MulSyscall)); + + syscall_map.insert( + SyscallCode::BLS12381_FP_ADD, + Arc::new(FpOpSyscall::::new(FieldOperation::Add)), + ); + + syscall_map.insert( + SyscallCode::BLS12381_FP_SUB, + Arc::new(FpOpSyscall::::new(FieldOperation::Sub)), + ); + + syscall_map.insert( + SyscallCode::BLS12381_FP_MUL, + Arc::new(FpOpSyscall::::new(FieldOperation::Mul)), + ); + + syscall_map.insert( + SyscallCode::BLS12381_FP2_ADD, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Add)), + ); + + syscall_map.insert( + SyscallCode::BLS12381_FP2_SUB, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Sub)), + ); + + syscall_map + .insert(SyscallCode::BLS12381_FP2_MUL, Arc::new(Fp2MulSyscall::::new())); + + syscall_map.insert( + SyscallCode::BN254_FP_ADD, + Arc::new(FpOpSyscall::::new(FieldOperation::Add)), + ); + + syscall_map.insert( + SyscallCode::BN254_FP_SUB, + Arc::new(FpOpSyscall::::new(FieldOperation::Sub)), + ); + + syscall_map.insert( + SyscallCode::BN254_FP_MUL, + Arc::new(FpOpSyscall::::new(FieldOperation::Mul)), + ); + + syscall_map.insert( + SyscallCode::BN254_FP2_ADD, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Add)), + ); + + syscall_map.insert( + SyscallCode::BN254_FP2_SUB, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Sub)), + ); + + syscall_map + .insert(SyscallCode::BN254_FP2_MUL, Arc::new(Fp2MulSyscall::::new())); + + syscall_map.insert(SyscallCode::ENTER_UNCONSTRAINED, Arc::new(EnterUnconstrainedSyscall)); + + syscall_map.insert(SyscallCode::EXIT_UNCONSTRAINED, Arc::new(ExitUnconstrainedSyscall)); + + syscall_map.insert(SyscallCode::WRITE, Arc::new(WriteSyscall)); + + syscall_map.insert(SyscallCode::COMMIT, Arc::new(CommitSyscall)); + + syscall_map.insert(SyscallCode::COMMIT_DEFERRED_PROOFS, Arc::new(CommitDeferredSyscall)); + + syscall_map.insert(SyscallCode::VERIFY_SP1_PROOF, Arc::new(VerifySyscall)); + + syscall_map.insert(SyscallCode::HINT_LEN, Arc::new(HintLenSyscall)); + + syscall_map.insert(SyscallCode::HINT_READ, Arc::new(HintReadSyscall)); + + syscall_map.insert( + SyscallCode::BLS12381_DECOMPRESS, + Arc::new(WeierstrassDecompressSyscall::::new()), + ); + + syscall_map +} diff --git a/crates/core/executor/src/syscalls/precompiles/edwards/add.rs b/crates/core/executor/src/syscalls/precompiles/edwards/add.rs new file mode 100644 index 0000000000..3074392b64 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/edwards/add.rs @@ -0,0 +1,31 @@ +use std::marker::PhantomData; + +use sp1_curves::{edwards::EdwardsParameters, EllipticCurve}; + +use crate::{ + events::create_ec_add_event, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct EdwardsAddAssignSyscall { + _phantom: PhantomData, +} + +impl EdwardsAddAssignSyscall { + /// Create a new instance of the [`EdwardsAddAssignSyscall`]. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +impl Syscall for EdwardsAddAssignSyscall { + fn num_extra_cycles(&self) -> u32 { + 1 + } + + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let event = create_ec_add_event::(rt, arg1, arg2); + rt.record_mut().ed_add_events.push(event); + None + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs b/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs new file mode 100644 index 0000000000..e4d90a87b0 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs @@ -0,0 +1,82 @@ +use std::marker::PhantomData; + +use sp1_curves::{ + curve25519_dalek::CompressedEdwardsY, + edwards::{ed25519::decompress, EdwardsParameters, WORDS_FIELD_ELEMENT}, + COMPRESSED_POINT_BYTES, +}; +use sp1_primitives::consts::{bytes_to_words_le, words_to_bytes_le}; + +use crate::{ + events::{EdDecompressEvent, MemoryReadRecord, MemoryWriteRecord}, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct EdwardsDecompressSyscall { + _phantom: PhantomData, +} + +impl EdwardsDecompressSyscall { + /// Create a new instance of the [`EdwardsDecompressSyscall`]. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +impl Syscall for EdwardsDecompressSyscall { + fn execute(&self, rt: &mut SyscallContext, arg1: u32, sign: u32) -> Option { + let start_clk = rt.clk; + let slice_ptr = arg1; + assert!(slice_ptr % 4 == 0, "Pointer must be 4-byte aligned."); + assert!(sign <= 1, "Sign bit must be 0 or 1."); + + let (y_memory_records_vec, y_vec) = + rt.mr_slice(slice_ptr + (COMPRESSED_POINT_BYTES as u32), WORDS_FIELD_ELEMENT); + let y_memory_records: [MemoryReadRecord; 8] = y_memory_records_vec.try_into().unwrap(); + + let sign_bool = sign != 0; + + let y_bytes: [u8; COMPRESSED_POINT_BYTES] = words_to_bytes_le(&y_vec); + + // Copy bytes into another array so we can modify the last byte and make CompressedEdwardsY, + // which we'll use to compute the expected X. + // Re-insert sign bit into last bit of Y for CompressedEdwardsY format + let mut compressed_edwards_y: [u8; COMPRESSED_POINT_BYTES] = y_bytes; + compressed_edwards_y[compressed_edwards_y.len() - 1] &= 0b0111_1111; + compressed_edwards_y[compressed_edwards_y.len() - 1] |= (sign as u8) << 7; + + // Compute actual decompressed X + let compressed_y = CompressedEdwardsY(compressed_edwards_y); + let decompressed = decompress(&compressed_y); + + let mut decompressed_x_bytes = decompressed.x.to_bytes_le(); + decompressed_x_bytes.resize(32, 0u8); + let decompressed_x_words: [u32; WORDS_FIELD_ELEMENT] = + bytes_to_words_le(&decompressed_x_bytes); + + // Write decompressed X into slice + let x_memory_records_vec = rt.mw_slice(slice_ptr, &decompressed_x_words); + let x_memory_records: [MemoryWriteRecord; 8] = x_memory_records_vec.try_into().unwrap(); + + let lookup_id = rt.syscall_lookup_id; + let shard = rt.current_shard(); + let channel = rt.current_channel(); + rt.record_mut().ed_decompress_events.push(EdDecompressEvent { + lookup_id, + shard, + channel, + clk: start_clk, + ptr: slice_ptr, + sign: sign_bool, + y_bytes, + decompressed_x_bytes: decompressed_x_bytes.try_into().unwrap(), + x_memory_records, + y_memory_records, + }); + None + } + + fn num_extra_cycles(&self) -> u32 { + 0 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/edwards/mod.rs b/crates/core/executor/src/syscalls/precompiles/edwards/mod.rs new file mode 100644 index 0000000000..adbf843703 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/edwards/mod.rs @@ -0,0 +1,2 @@ +pub mod add; +pub mod decompress; diff --git a/crates/core/executor/src/syscalls/precompiles/fptower/fp.rs b/crates/core/executor/src/syscalls/precompiles/fptower/fp.rs new file mode 100644 index 0000000000..93ea8f3f77 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/fptower/fp.rs @@ -0,0 +1,100 @@ +use num::BigUint; +use sp1_curves::{ + params::NumWords, + weierstrass::{FieldType, FpOpField}, +}; +use std::marker::PhantomData; +use typenum::Unsigned; + +use crate::{ + events::{FieldOperation, FpOpEvent}, + syscalls::{Syscall, SyscallContext}, +}; + +pub struct FpOpSyscall

{ + op: FieldOperation, + _marker: PhantomData

, +} + +impl

FpOpSyscall

{ + pub const fn new(op: FieldOperation) -> Self { + Self { op, _marker: PhantomData } + } +} + +impl Syscall for FpOpSyscall

{ + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let clk = rt.clk; + let x_ptr = arg1; + if x_ptr % 4 != 0 { + panic!(); + } + let y_ptr = arg2; + if y_ptr % 4 != 0 { + panic!(); + } + + let num_words =

::WordsFieldElement::USIZE; + + let x = rt.slice_unsafe(x_ptr, num_words); + let (y_memory_records, y) = rt.mr_slice(y_ptr, num_words); + + let modulus = &BigUint::from_bytes_le(P::MODULUS); + let a = BigUint::from_slice(&x) % modulus; + let b = BigUint::from_slice(&y) % modulus; + + let result = match self.op { + FieldOperation::Add => (a + b) % modulus, + FieldOperation::Sub => ((a + modulus) - b) % modulus, + FieldOperation::Mul => (a * b) % modulus, + _ => panic!("Unsupported operation"), + }; + let mut result = result.to_u32_digits(); + result.resize(num_words, 0); + + rt.clk += 1; + let x_memory_records = rt.mw_slice(x_ptr, &result); + + let lookup_id = rt.syscall_lookup_id as usize; + let shard = rt.current_shard(); + let channel = rt.current_channel(); + match P::FIELD_TYPE { + FieldType::Bn254 => { + rt.record_mut().bn254_fp_events.push(FpOpEvent { + lookup_id, + shard, + channel, + clk, + x_ptr, + x, + y_ptr, + y, + op: self.op, + x_memory_records, + y_memory_records, + }); + } + FieldType::Bls12381 => { + rt.record_mut().bls12381_fp_events.push(FpOpEvent { + lookup_id, + shard, + channel, + clk, + x_ptr, + x, + y_ptr, + y, + op: self.op, + x_memory_records, + y_memory_records, + }); + } + } + + None + } + + fn num_extra_cycles(&self) -> u32 { + 1 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs new file mode 100644 index 0000000000..6d737db27f --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs @@ -0,0 +1,108 @@ +use num::BigUint; +use sp1_curves::{ + params::NumWords, + weierstrass::{FieldType, FpOpField}, +}; +use std::marker::PhantomData; +use typenum::Unsigned; + +use crate::{ + events::{FieldOperation, Fp2AddSubEvent}, + syscalls::{Syscall, SyscallContext}, +}; + +pub struct Fp2AddSubSyscall

{ + op: FieldOperation, + _marker: PhantomData

, +} + +impl

Fp2AddSubSyscall

{ + pub const fn new(op: FieldOperation) -> Self { + Self { op, _marker: PhantomData } + } +} + +impl Syscall for Fp2AddSubSyscall

{ + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let clk = rt.clk; + let x_ptr = arg1; + if x_ptr % 4 != 0 { + panic!(); + } + let y_ptr = arg2; + if y_ptr % 4 != 0 { + panic!(); + } + + let num_words =

::WordsCurvePoint::USIZE; + + let x = rt.slice_unsafe(x_ptr, num_words); + let (y_memory_records, y) = rt.mr_slice(y_ptr, num_words); + rt.clk += 1; + + let (ac0, ac1) = x.split_at(x.len() / 2); + let (bc0, bc1) = y.split_at(y.len() / 2); + + let ac0 = &BigUint::from_slice(ac0); + let ac1 = &BigUint::from_slice(ac1); + let bc0 = &BigUint::from_slice(bc0); + let bc1 = &BigUint::from_slice(bc1); + let modulus = &BigUint::from_bytes_le(P::MODULUS); + + let (c0, c1) = match self.op { + FieldOperation::Add => ((ac0 + bc0) % modulus, (ac1 + bc1) % modulus), + FieldOperation::Sub => { + ((ac0 + modulus - bc0) % modulus, (ac1 + modulus - bc1) % modulus) + } + _ => panic!("Invalid operation"), + }; + + let mut result = + c0.to_u32_digits().into_iter().chain(c1.to_u32_digits()).collect::>(); + + result.resize(num_words, 0); + let x_memory_records = rt.mw_slice(x_ptr, &result); + + let lookup_id = rt.syscall_lookup_id as usize; + let shard = rt.current_shard(); + let channel = rt.current_channel(); + let op = self.op; + match P::FIELD_TYPE { + FieldType::Bn254 => { + rt.record_mut().bn254_fp2_addsub_events.push(Fp2AddSubEvent { + lookup_id, + shard, + channel, + clk, + op, + x_ptr, + x, + y_ptr, + y, + x_memory_records, + y_memory_records, + }); + } + FieldType::Bls12381 => { + rt.record_mut().bls12381_fp2_addsub_events.push(Fp2AddSubEvent { + lookup_id, + shard, + channel, + clk, + op, + x_ptr, + x, + y_ptr, + y, + x_memory_records, + y_memory_records, + }); + } + } + None + } + + fn num_extra_cycles(&self) -> u32 { + 1 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/fptower/fp2_mul.rs b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_mul.rs new file mode 100644 index 0000000000..d4e4748d9b --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_mul.rs @@ -0,0 +1,100 @@ +use std::marker::PhantomData; + +use num::BigUint; +use sp1_curves::{ + params::NumWords, + weierstrass::{FieldType, FpOpField}, +}; +use typenum::Unsigned; + +use crate::{ + events::Fp2MulEvent, + syscalls::{Syscall, SyscallContext}, +}; + +pub struct Fp2MulSyscall

{ + _marker: PhantomData

, +} + +impl

Fp2MulSyscall

{ + pub const fn new() -> Self { + Self { _marker: PhantomData } + } +} + +impl Syscall for Fp2MulSyscall

{ + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let clk = rt.clk; + let x_ptr = arg1; + if x_ptr % 4 != 0 { + panic!(); + } + let y_ptr = arg2; + if y_ptr % 4 != 0 { + panic!(); + } + + let num_words =

::WordsCurvePoint::USIZE; + + let x = rt.slice_unsafe(x_ptr, num_words); + let (y_memory_records, y) = rt.mr_slice(y_ptr, num_words); + rt.clk += 1; + + let (ac0, ac1) = x.split_at(x.len() / 2); + let (bc0, bc1) = y.split_at(y.len() / 2); + + let ac0 = &BigUint::from_slice(ac0); + let ac1 = &BigUint::from_slice(ac1); + let bc0 = &BigUint::from_slice(bc0); + let bc1 = &BigUint::from_slice(bc1); + let modulus = &BigUint::from_bytes_le(P::MODULUS); + + #[allow(clippy::match_bool)] + let c0 = match (ac0 * bc0) % modulus < (ac1 * bc1) % modulus { + true => ((modulus + (ac0 * bc0) % modulus) - (ac1 * bc1) % modulus) % modulus, + false => ((ac0 * bc0) % modulus - (ac1 * bc1) % modulus) % modulus, + }; + let c1 = ((ac0 * bc1) % modulus + (ac1 * bc0) % modulus) % modulus; + + let mut result = + c0.to_u32_digits().into_iter().chain(c1.to_u32_digits()).collect::>(); + + result.resize(num_words, 0); + let x_memory_records = rt.mw_slice(x_ptr, &result); + + let lookup_id = rt.syscall_lookup_id as usize; + let shard = rt.current_shard(); + let channel = rt.current_channel(); + match P::FIELD_TYPE { + FieldType::Bn254 => rt.record_mut().bn254_fp2_mul_events.push(Fp2MulEvent { + lookup_id, + shard, + channel, + clk, + x_ptr, + x, + y_ptr, + y, + x_memory_records, + y_memory_records, + }), + FieldType::Bls12381 => rt.record_mut().bls12381_fp2_mul_events.push(Fp2MulEvent { + lookup_id, + shard, + channel, + clk, + x_ptr, + x, + y_ptr, + y, + x_memory_records, + y_memory_records, + }), + }; + None + } + + fn num_extra_cycles(&self) -> u32 { + 1 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/fptower/mod.rs b/crates/core/executor/src/syscalls/precompiles/fptower/mod.rs new file mode 100644 index 0000000000..66c2413eb4 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/fptower/mod.rs @@ -0,0 +1,7 @@ +mod fp; +mod fp2_addsub; +mod fp2_mul; + +pub use fp::*; +pub use fp2_addsub::*; +pub use fp2_mul::*; diff --git a/crates/core/executor/src/syscalls/precompiles/keccak256/mod.rs b/crates/core/executor/src/syscalls/precompiles/keccak256/mod.rs new file mode 100644 index 0000000000..94d0bb39a0 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/keccak256/mod.rs @@ -0,0 +1 @@ +pub mod permute; diff --git a/crates/core/executor/src/syscalls/precompiles/keccak256/permute.rs b/crates/core/executor/src/syscalls/precompiles/keccak256/permute.rs new file mode 100644 index 0000000000..70c64950dd --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/keccak256/permute.rs @@ -0,0 +1,77 @@ +use crate::{ + events::KeccakPermuteEvent, + syscalls::{Syscall, SyscallContext}, +}; + +use tiny_keccak::keccakf; + +pub(crate) const STATE_SIZE: usize = 25; + +// The permutation state is 25 u64's. Our word size is 32 bits, so it is 50 words. +pub const STATE_NUM_WORDS: usize = STATE_SIZE * 2; + +pub(crate) struct Keccak256PermuteSyscall; + +impl Syscall for Keccak256PermuteSyscall { + fn num_extra_cycles(&self) -> u32 { + 1 + } + + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let start_clk = rt.clk; + let state_ptr = arg1; + if arg2 != 0 { + panic!("Expected arg2 to be 0, got {arg2}"); + } + + let mut state_read_records = Vec::new(); + let mut state_write_records = Vec::new(); + + let mut state = Vec::new(); + + let (state_records, state_values) = rt.mr_slice(state_ptr, STATE_NUM_WORDS); + state_read_records.extend_from_slice(&state_records); + + for values in state_values.chunks_exact(2) { + let least_sig = values[0]; + let most_sig = values[1]; + state.push(least_sig as u64 + ((most_sig as u64) << 32)); + } + + let saved_state = state.clone(); + + let mut state = state.try_into().unwrap(); + keccakf(&mut state); + + // Increment the clk by 1 before writing because we read from memory at start_clk. + rt.clk += 1; + let mut values_to_write = Vec::new(); + for i in 0..STATE_SIZE { + let most_sig = ((state[i] >> 32) & 0xFFFFFFFF) as u32; + let least_sig = (state[i] & 0xFFFFFFFF) as u32; + values_to_write.push(least_sig); + values_to_write.push(most_sig); + } + + let write_records = rt.mw_slice(state_ptr, values_to_write.as_slice()); + state_write_records.extend_from_slice(&write_records); + + // Push the Keccak permute event. + let shard = rt.current_shard(); + let channel = rt.current_channel(); + let lookup_id = rt.syscall_lookup_id; + rt.record_mut().keccak_permute_events.push(KeccakPermuteEvent { + lookup_id, + shard, + channel, + clk: start_clk, + pre_state: saved_state.as_slice().try_into().unwrap(), + post_state: state.as_slice().try_into().unwrap(), + state_read_records, + state_write_records, + state_addr: state_ptr, + }); + + None + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/mod.rs b/crates/core/executor/src/syscalls/precompiles/mod.rs new file mode 100644 index 0000000000..f07da94609 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/mod.rs @@ -0,0 +1,6 @@ +pub mod edwards; +pub mod fptower; +pub mod keccak256; +pub mod sha256; +pub mod uint256; +pub mod weierstrass; diff --git a/core/src/syscall/precompiles/sha256/compress/execute.rs b/crates/core/executor/src/syscalls/precompiles/sha256/compress.rs similarity index 73% rename from core/src/syscall/precompiles/sha256/compress/execute.rs rename to crates/core/executor/src/syscalls/precompiles/sha256/compress.rs index 5ed33dd2b7..1c8317cfc9 100644 --- a/core/src/syscall/precompiles/sha256/compress/execute.rs +++ b/crates/core/executor/src/syscalls/precompiles/sha256/compress.rs @@ -1,17 +1,27 @@ -use super::ShaCompressChip; use crate::{ - runtime::Syscall, - syscall::precompiles::{ - sha256::{ShaCompressEvent, SHA_COMPRESS_K}, - SyscallContext, - }, + events::ShaCompressEvent, + syscalls::{Syscall, SyscallContext}, }; -impl Syscall for ShaCompressChip { +pub const SHA_COMPRESS_K: [u32; 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +]; + +pub(crate) struct Sha256CompressSyscall; + +impl Syscall for Sha256CompressSyscall { fn num_extra_cycles(&self) -> u32 { 1 } + #[allow(clippy::many_single_char_names)] fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { let w_ptr = arg1; let h_ptr = arg2; diff --git a/core/src/syscall/precompiles/sha256/extend/execute.rs b/crates/core/executor/src/syscalls/precompiles/sha256/extend.rs similarity index 84% rename from core/src/syscall/precompiles/sha256/extend/execute.rs rename to crates/core/executor/src/syscalls/precompiles/sha256/extend.rs index d9b1a70e09..842fc678b8 100644 --- a/core/src/syscall/precompiles/sha256/extend/execute.rs +++ b/crates/core/executor/src/syscalls/precompiles/sha256/extend.rs @@ -1,11 +1,11 @@ use crate::{ - runtime::Syscall, - syscall::precompiles::{sha256::ShaExtendEvent, SyscallContext}, + events::ShaExtendEvent, + syscalls::{Syscall, SyscallContext}, }; -use super::ShaExtendChip; +pub(crate) struct Sha256ExtendSyscall; -impl Syscall for ShaExtendChip { +impl Syscall for Sha256ExtendSyscall { fn num_extra_cycles(&self) -> u32 { 48 } @@ -13,9 +13,7 @@ impl Syscall for ShaExtendChip { fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { let clk_init = rt.clk; let w_ptr = arg1; - if arg2 != 0 { - panic!("arg2 must be 0") - } + assert!(arg2 == 0, "arg2 must be 0"); let w_ptr_init = w_ptr; let mut w_i_minus_15_reads = Vec::new(); @@ -49,10 +47,7 @@ impl Syscall for ShaExtendChip { w_i_minus_7_reads.push(record); // Compute `w_i`. - let w_i = s1 - .wrapping_add(w_i_minus_16) - .wrapping_add(s0) - .wrapping_add(w_i_minus_7); + let w_i = s1.wrapping_add(w_i_minus_16).wrapping_add(s0).wrapping_add(w_i_minus_7); // Write w[i]. w_i_writes.push(rt.mw(w_ptr + i * 4, w_i)); diff --git a/crates/core/executor/src/syscalls/precompiles/sha256/mod.rs b/crates/core/executor/src/syscalls/precompiles/sha256/mod.rs new file mode 100644 index 0000000000..d54c053f94 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/sha256/mod.rs @@ -0,0 +1,2 @@ +pub mod compress; +pub mod extend; diff --git a/crates/core/executor/src/syscalls/precompiles/uint256.rs b/crates/core/executor/src/syscalls/precompiles/uint256.rs new file mode 100644 index 0000000000..4592f999fc --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/uint256.rs @@ -0,0 +1,85 @@ +use num::{BigUint, One, Zero}; + +use sp1_curves::edwards::WORDS_FIELD_ELEMENT; +use sp1_primitives::consts::{bytes_to_words_le, words_to_bytes_le_vec, WORD_SIZE}; + +use crate::{ + events::Uint256MulEvent, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct Uint256MulSyscall; + +impl Syscall for Uint256MulSyscall { + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let clk = rt.clk; + + let x_ptr = arg1; + if x_ptr % 4 != 0 { + panic!(); + } + let y_ptr = arg2; + if y_ptr % 4 != 0 { + panic!(); + } + + // First read the words for the x value. We can read a slice_unsafe here because we write + // the computed result to x later. + let x = rt.slice_unsafe(x_ptr, WORDS_FIELD_ELEMENT); + + // Read the y value. + let (y_memory_records, y) = rt.mr_slice(y_ptr, WORDS_FIELD_ELEMENT); + + // The modulus is stored after the y value. We increment the pointer by the number of words. + let modulus_ptr = y_ptr + WORDS_FIELD_ELEMENT as u32 * WORD_SIZE as u32; + let (modulus_memory_records, modulus) = rt.mr_slice(modulus_ptr, WORDS_FIELD_ELEMENT); + + // Get the BigUint values for x, y, and the modulus. + let uint256_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&x)); + let uint256_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&y)); + let uint256_modulus = BigUint::from_bytes_le(&words_to_bytes_le_vec(&modulus)); + + // Perform the multiplication and take the result modulo the modulus. + let result: BigUint = if uint256_modulus.is_zero() { + let modulus = BigUint::one() << 256; + (uint256_x * uint256_y) % modulus + } else { + (uint256_x * uint256_y) % uint256_modulus + }; + + let mut result_bytes = result.to_bytes_le(); + result_bytes.resize(32, 0u8); // Pad the result to 32 bytes. + + // Convert the result to little endian u32 words. + let result = bytes_to_words_le::<8>(&result_bytes); + + // Increment clk so that the write is not at the same cycle as the read. + rt.clk += 1; + // Write the result to x and keep track of the memory records. + let x_memory_records = rt.mw_slice(x_ptr, &result); + + let lookup_id = rt.syscall_lookup_id; + let shard = rt.current_shard(); + let channel = rt.current_channel(); + rt.record_mut().uint256_mul_events.push(Uint256MulEvent { + lookup_id, + shard, + channel, + clk, + x_ptr, + x, + y_ptr, + y, + modulus, + x_memory_records, + y_memory_records, + modulus_memory_records, + }); + + None + } + + fn num_extra_cycles(&self) -> u32 { + 1 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs new file mode 100644 index 0000000000..9d39ca325a --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs @@ -0,0 +1,36 @@ +use std::marker::PhantomData; + +use sp1_curves::{CurveType, EllipticCurve}; + +use crate::{ + events::create_ec_add_event, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct WeierstrassAddAssignSyscall { + _phantom: PhantomData, +} + +impl WeierstrassAddAssignSyscall { + /// Create a new instance of the [`WeierstrassAddAssignSyscall`]. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +impl Syscall for WeierstrassAddAssignSyscall { + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let event = create_ec_add_event::(rt, arg1, arg2); + match E::CURVE_TYPE { + CurveType::Secp256k1 => rt.record_mut().secp256k1_add_events.push(event), + CurveType::Bn254 => rt.record_mut().bn254_add_events.push(event), + CurveType::Bls12381 => rt.record_mut().bls12381_add_events.push(event), + _ => panic!("Unsupported curve"), + } + None + } + + fn num_extra_cycles(&self) -> u32 { + 1 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs new file mode 100644 index 0000000000..a2b476281e --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs @@ -0,0 +1,35 @@ +use std::marker::PhantomData; + +use sp1_curves::{CurveType, EllipticCurve}; + +use crate::{ + events::create_ec_decompress_event, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct WeierstrassDecompressSyscall { + _phantom: std::marker::PhantomData, +} + +impl WeierstrassDecompressSyscall { + /// Create a new instance of the [`WeierstrassDecompressSyscall`]. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +impl Syscall for WeierstrassDecompressSyscall { + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let event = create_ec_decompress_event::(rt, arg1, arg2); + match E::CURVE_TYPE { + CurveType::Secp256k1 => rt.record_mut().k256_decompress_events.push(event), + CurveType::Bls12381 => rt.record_mut().bls12381_decompress_events.push(event), + _ => panic!("Unsupported curve"), + } + None + } + + fn num_extra_cycles(&self) -> u32 { + 0 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs new file mode 100644 index 0000000000..507e78f05c --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs @@ -0,0 +1,36 @@ +use std::marker::PhantomData; + +use sp1_curves::{CurveType, EllipticCurve}; + +use crate::{ + events::create_ec_double_event, + syscalls::{Syscall, SyscallContext}, +}; + +pub(crate) struct WeierstrassDoubleAssignSyscall { + _phantom: std::marker::PhantomData, +} + +impl WeierstrassDoubleAssignSyscall { + /// Create a new instance of the [`WeierstrassDoubleAssignSyscall`]. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +impl Syscall for WeierstrassDoubleAssignSyscall { + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let event = create_ec_double_event::(rt, arg1, arg2); + match E::CURVE_TYPE { + CurveType::Secp256k1 => rt.record_mut().secp256k1_double_events.push(event), + CurveType::Bn254 => rt.record_mut().bn254_double_events.push(event), + CurveType::Bls12381 => rt.record_mut().bls12381_double_events.push(event), + _ => panic!("Unsupported curve"), + } + None + } + + fn num_extra_cycles(&self) -> u32 { + 0 + } +} diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/mod.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/mod.rs new file mode 100644 index 0000000000..25964fae20 --- /dev/null +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/mod.rs @@ -0,0 +1,3 @@ +pub mod add; +pub mod decompress; +pub mod double; diff --git a/core/src/syscall/unconstrained.rs b/crates/core/executor/src/syscalls/unconstrained.rs similarity index 68% rename from core/src/syscall/unconstrained.rs rename to crates/core/executor/src/syscalls/unconstrained.rs index ab9456ce64..091748fb0c 100644 --- a/core/src/syscall/unconstrained.rs +++ b/crates/core/executor/src/syscalls/unconstrained.rs @@ -1,16 +1,12 @@ -use std::collections::HashMap; +use hashbrown::HashMap; -use crate::runtime::{ForkState, Syscall, SyscallContext}; +use crate::{state::ForkState, ExecutorMode}; -pub struct SyscallEnterUnconstrained; +use super::{Syscall, SyscallContext}; -impl SyscallEnterUnconstrained { - pub const fn new() -> Self { - Self - } -} +pub(crate) struct EnterUnconstrainedSyscall; -impl Syscall for SyscallEnterUnconstrained { +impl Syscall for EnterUnconstrainedSyscall { fn execute(&self, ctx: &mut SyscallContext, _: u32, _: u32) -> Option { if ctx.rt.unconstrained { panic!("Unconstrained block is already active."); @@ -23,22 +19,16 @@ impl Syscall for SyscallEnterUnconstrained { memory_diff: HashMap::default(), record: std::mem::take(&mut ctx.rt.record), op_record: std::mem::take(&mut ctx.rt.memory_accesses), - emit_events: ctx.rt.emit_events, + executor_mode: ctx.rt.executor_mode, }; - ctx.rt.emit_events = false; + ctx.rt.executor_mode = ExecutorMode::Simple; Some(1) } } -pub struct SyscallExitUnconstrained; - -impl SyscallExitUnconstrained { - pub const fn new() -> Self { - Self - } -} +pub(crate) struct ExitUnconstrainedSyscall; -impl Syscall for SyscallExitUnconstrained { +impl Syscall for ExitUnconstrainedSyscall { fn execute(&self, ctx: &mut SyscallContext, _: u32, _: u32) -> Option { // Reset the state of the runtime. if ctx.rt.unconstrained { @@ -58,22 +48,10 @@ impl Syscall for SyscallExitUnconstrained { } ctx.rt.record = std::mem::take(&mut ctx.rt.unconstrained_state.record); ctx.rt.memory_accesses = std::mem::take(&mut ctx.rt.unconstrained_state.op_record); - ctx.rt.emit_events = ctx.rt.unconstrained_state.emit_events; + ctx.rt.executor_mode = ctx.rt.unconstrained_state.executor_mode; ctx.rt.unconstrained = false; } ctx.rt.unconstrained_state = ForkState::default(); Some(0) } } - -impl Default for SyscallEnterUnconstrained { - fn default() -> Self { - Self::new() - } -} - -impl Default for SyscallExitUnconstrained { - fn default() -> Self { - Self::new() - } -} diff --git a/core/src/syscall/verify.rs b/crates/core/executor/src/syscalls/verify.rs similarity index 63% rename from core/src/syscall/verify.rs rename to crates/core/executor/src/syscalls/verify.rs index 1909da9941..cf314b1ad8 100644 --- a/core/src/syscall/verify.rs +++ b/crates/core/executor/src/syscalls/verify.rs @@ -1,19 +1,9 @@ -use core::panic; +use super::{Syscall, SyscallContext}; -use crate::runtime::{Syscall, SyscallContext}; +pub(crate) struct VerifySyscall; -/// Verifies an SP1 recursive verifier proof. Note that this syscall only verifies the proof during -/// runtime. The actual constraint-level verification is deferred to the recursive layer, where -/// proofs are witnessed and verified in order to reconstruct the deferred_proofs_digest. -pub struct SyscallVerifySP1Proof; - -impl SyscallVerifySP1Proof { - pub const fn new() -> Self { - Self - } -} - -impl Syscall for SyscallVerifySP1Proof { +impl Syscall for VerifySyscall { + #[allow(clippy::mut_mut)] fn execute(&self, ctx: &mut SyscallContext, vkey_ptr: u32, pv_digest_ptr: u32) -> Option { let rt = &mut ctx.rt; @@ -22,13 +12,9 @@ impl Syscall for SyscallVerifySP1Proof { // pv_digest_ptr is a pointer to [u32; 8] which contains the public values digest. assert_eq!(pv_digest_ptr % 4, 0, "pv_digest_ptr must be word-aligned"); - let vkey = (0..8) - .map(|i| rt.word(vkey_ptr + i * 4)) - .collect::>(); + let vkey = (0..8).map(|i| rt.word(vkey_ptr + i * 4)).collect::>(); - let pv_digest = (0..8) - .map(|i| rt.word(pv_digest_ptr + i * 4)) - .collect::>(); + let pv_digest = (0..8).map(|i| rt.word(pv_digest_ptr + i * 4)).collect::>(); let proof_index = rt.state.proof_stream_ptr; if proof_index >= rt.state.proof_stream.len() { diff --git a/crates/core/executor/src/syscalls/write.rs b/crates/core/executor/src/syscalls/write.rs new file mode 100644 index 0000000000..d40133903f --- /dev/null +++ b/crates/core/executor/src/syscalls/write.rs @@ -0,0 +1,156 @@ +use sp1_primitives::consts::num_to_comma_separated; + +use crate::{Executor, Register}; + +use super::{Syscall, SyscallContext}; + +pub(crate) struct WriteSyscall; + +impl Syscall for WriteSyscall { + /// Handle writes to file descriptors during execution. + /// + /// If stdout (fd = 1): + /// - If the stream is a cycle tracker, either log the cycle tracker or accumulate it in the + /// report. + /// - Else, print the stream to stdout. + /// + /// If stderr (fd = 2): + /// - Print the stream to stderr. + /// + /// If fd = 3: + /// - Update the public value stream. + /// + /// If fd = 4: + /// - Update the input stream. + /// + /// If the fd matches a hook in the hook registry, invoke the hook. + /// + /// Else, log a warning. + #[allow(clippy::pedantic)] + fn execute(&self, ctx: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + let a2 = Register::X12; + let rt = &mut ctx.rt; + let fd = arg1; + let write_buf = arg2; + let nbytes = rt.register(a2); + // Read nbytes from memory starting at write_buf. + let bytes = (0..nbytes).map(|i| rt.byte(write_buf + i)).collect::>(); + let slice = bytes.as_slice(); + if fd == 1 { + let s = core::str::from_utf8(slice).unwrap(); + match parse_cycle_tracker_command(s) { + Some(command) => handle_cycle_tracker_command(rt, command), + None => { + // If the string does not match any known command, print it to stdout. + let flush_s = update_io_buf(ctx, fd, s); + if !flush_s.is_empty() { + flush_s.into_iter().for_each(|line| println!("stdout: {}", line)); + } + } + } + } else if fd == 2 { + let s = core::str::from_utf8(slice).unwrap(); + let flush_s = update_io_buf(ctx, fd, s); + if !flush_s.is_empty() { + flush_s.into_iter().for_each(|line| println!("stderr: {}", line)); + } + } else if fd == 3 { + rt.state.public_values_stream.extend_from_slice(slice); + } else if fd == 4 { + rt.state.input_stream.push(slice.to_vec()); + } else if let Some(mut hook) = rt.hook_registry.get(fd) { + let res = hook.invoke_hook(rt.hook_env(), slice); + // Add result vectors to the beginning of the stream. + let ptr = rt.state.input_stream_ptr; + rt.state.input_stream.splice(ptr..ptr, res); + } else { + tracing::warn!("tried to write to unknown file descriptor {fd}"); + } + None + } +} + +/// An enum representing the different cycle tracker commands. +#[derive(Clone)] +enum CycleTrackerCommand { + Start(String), + End(String), + ReportStart(String), + ReportEnd(String), +} + +/// Parse a cycle tracker command from a string. If the string does not match any known command, +/// returns None. +fn parse_cycle_tracker_command(s: &str) -> Option { + let (command, fn_name) = s.split_once(':')?; + let trimmed_name = fn_name.trim().to_string(); + + match command { + "cycle-tracker-start" => Some(CycleTrackerCommand::Start(trimmed_name)), + "cycle-tracker-end" => Some(CycleTrackerCommand::End(trimmed_name)), + "cycle-tracker-report-start" => Some(CycleTrackerCommand::ReportStart(trimmed_name)), + "cycle-tracker-report-end" => Some(CycleTrackerCommand::ReportEnd(trimmed_name)), + _ => None, + } +} + +/// Handle a cycle tracker command. +fn handle_cycle_tracker_command(rt: &mut Executor, command: CycleTrackerCommand) { + match command { + CycleTrackerCommand::Start(name) | CycleTrackerCommand::ReportStart(name) => { + start_cycle_tracker(rt, &name); + } + CycleTrackerCommand::End(name) => { + end_cycle_tracker(rt, &name); + } + CycleTrackerCommand::ReportEnd(name) => { + // Attempt to end the cycle tracker and accumulate the total cycles in the fn_name's + // entry in the ExecutionReport. + if let Some(total_cycles) = end_cycle_tracker(rt, &name) { + rt.report + .cycle_tracker + .entry(name.to_string()) + .and_modify(|cycles| *cycles += total_cycles) + .or_insert(total_cycles); + } + } + } +} + +/// Start tracking cycles for the given name at the specific depth and print out the log. +fn start_cycle_tracker(rt: &mut Executor, name: &str) { + let depth = rt.cycle_tracker.len() as u32; + rt.cycle_tracker.insert(name.to_string(), (rt.state.global_clk, depth)); + let padding = "│ ".repeat(depth as usize); + log::info!("{}┌╴{}", padding, name); +} + +/// End tracking cycles for the given name, print out the log, and return the total number of cycles +/// in the span. If the name is not found in the cycle tracker cache, returns None. +fn end_cycle_tracker(rt: &mut Executor, name: &str) -> Option { + if let Some((start, depth)) = rt.cycle_tracker.remove(name) { + let padding = "│ ".repeat(depth as usize); + let total_cycles = rt.state.global_clk - start; + log::info!("{}└╴{} cycles", padding, num_to_comma_separated(total_cycles)); + return Some(total_cycles); + } + None +} + +/// Update the io buffer for the given file descriptor with the given string. +#[allow(clippy::mut_mut)] +fn update_io_buf(ctx: &mut SyscallContext, fd: u32, s: &str) -> Vec { + let rt = &mut ctx.rt; + let entry = rt.io_buf.entry(fd).or_default(); + entry.push_str(s); + if entry.contains('\n') { + // Return lines except for the last from buf. + let prev_buf = std::mem::take(entry); + let mut lines = prev_buf.split('\n').collect::>(); + let last = lines.pop().unwrap_or(""); + *entry = last.to_string(); + lines.into_iter().map(std::string::ToString::to_string).collect::>() + } else { + vec![] + } +} diff --git a/core/CHANGELOG.md b/crates/core/machine/CHANGELOG.md similarity index 97% rename from core/CHANGELOG.md rename to crates/core/machine/CHANGELOG.md index 2eeb1b9a9e..8d1e6df781 100644 --- a/core/CHANGELOG.md +++ b/crates/core/machine/CHANGELOG.md @@ -7,25 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-core-machine-v1.2.0-rc1) - 2024-08-23 + +### Added + +- gas ([#1354](https://github.com/succinctlabs/sp1/pull/1354)) + +### Fixed + +- remove field op comment +- fix fptower tests +- fix imports +- cargo check on tests + +### Other + +- precompile guide +- use crate `vec_map`, box large `Instruction` variants ([#1360](https://github.com/succinctlabs/sp1/pull/1360)) +- update version +- merge dev into experimental pt 2 ([#1341](https://github.com/succinctlabs/sp1/pull/1341)) +- resolve merge conflicts between dev and experimental +- refactor + cleanup core crates + ## [1.1.0](https://github.com/succinctlabs/sp1/compare/sp1-core-v1.0.1...sp1-core-v1.1.0) - 2024-08-02 ### Added + - experimental gpu support ([#1219](https://github.com/succinctlabs/sp1/pull/1219)) - update tg ([#1214](https://github.com/succinctlabs/sp1/pull/1214)) - streaming recursion ([#1175](https://github.com/succinctlabs/sp1/pull/1175)) - streaming prover for core ([#1146](https://github.com/succinctlabs/sp1/pull/1146)) ### Fixed + - memory global generate_dependencies ([#1220](https://github.com/succinctlabs/sp1/pull/1220)) - device oom ([#1202](https://github.com/succinctlabs/sp1/pull/1202)) - cycle tracking logs ([#1178](https://github.com/succinctlabs/sp1/pull/1178)) - UB from `OpcodeSpecificCols` union ([#1050](https://github.com/succinctlabs/sp1/pull/1050)) ### Other + - merge main into dev ([#1180](https://github.com/succinctlabs/sp1/pull/1180)) - prover trait cleanup ([#1170](https://github.com/succinctlabs/sp1/pull/1170)) -- *(deps)* bump arrayref from 0.3.7 to 0.3.8 ([#1154](https://github.com/succinctlabs/sp1/pull/1154)) -- *(deps)* bump thiserror from 1.0.61 to 1.0.63 ([#1136](https://github.com/succinctlabs/sp1/pull/1136)) +- _(deps)_ bump arrayref from 0.3.7 to 0.3.8 ([#1154](https://github.com/succinctlabs/sp1/pull/1154)) +- _(deps)_ bump thiserror from 1.0.61 to 1.0.63 ([#1136](https://github.com/succinctlabs/sp1/pull/1136)) - generate dep optimizations ([#1125](https://github.com/succinctlabs/sp1/pull/1125)) - add audit reports ([#1142](https://github.com/succinctlabs/sp1/pull/1142)) diff --git a/core/Cargo.toml b/crates/core/machine/Cargo.toml similarity index 91% rename from core/Cargo.toml rename to crates/core/machine/Cargo.toml index 12a2592294..ac01767a9f 100644 --- a/core/Cargo.toml +++ b/crates/core/machine/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "sp1-core" +name = "sp1-core-machine" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -69,21 +69,22 @@ bytemuck = "1.16.0" hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] } static_assertions = "1.1.0" +sp1-stark = { workspace = true } +sp1-core-executor = { workspace = true } +sp1-curves = { workspace = true } + [dev-dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } criterion = "0.5.1" num = { version = "0.4.3", features = ["rand"] } rand = "0.8.5" sp1-zkvm = { workspace = true } +sp1-core-executor = { workspace = true, features = ["programs"] } [features] neon = ["p3-blake3/neon"] programs = [] debug = [] -[[bench]] -harness = false -name = "main" - [lib] bench = false diff --git a/crates/core/machine/src/air/memory.rs b/crates/core/machine/src/air/memory.rs new file mode 100644 index 0000000000..8d0c9fb909 --- /dev/null +++ b/crates/core/machine/src/air/memory.rs @@ -0,0 +1,190 @@ +use std::iter::once; + +use p3_air::AirBuilder; +use p3_field::AbstractField; +use sp1_core_executor::ByteOpcode; +use sp1_stark::{ + air::{AirInteraction, BaseAirBuilder, ByteAirBuilder}, + InteractionKind, +}; + +use crate::memory::{MemoryAccessCols, MemoryCols}; + +pub trait MemoryAirBuilder: BaseAirBuilder { + /// Constrain a memory read or write. + /// + /// This method verifies that a memory access timestamp (shard, clk) is greater than the + /// previous access's timestamp. It will also add to the memory argument. + fn eval_memory_access + Clone>( + &mut self, + shard: impl Into, + channel: impl Into, + clk: impl Into, + addr: impl Into, + memory_access: &impl MemoryCols, + do_check: impl Into, + ) { + let do_check: Self::Expr = do_check.into(); + let shard: Self::Expr = shard.into(); + let channel: Self::Expr = channel.into(); + let clk: Self::Expr = clk.into(); + let mem_access = memory_access.access(); + + self.assert_bool(do_check.clone()); + + // Verify that the current memory access time is greater than the previous's. + self.eval_memory_access_timestamp( + mem_access, + do_check.clone(), + shard.clone(), + channel, + clk.clone(), + ); + + // Add to the memory argument. + let addr = addr.into(); + let prev_shard = mem_access.prev_shard.clone().into(); + let prev_clk = mem_access.prev_clk.clone().into(); + let prev_values = once(prev_shard) + .chain(once(prev_clk)) + .chain(once(addr.clone())) + .chain(memory_access.prev_value().clone().map(Into::into)) + .collect(); + let current_values = once(shard) + .chain(once(clk)) + .chain(once(addr.clone())) + .chain(memory_access.value().clone().map(Into::into)) + .collect(); + + // The previous values get sent with multiplicity = 1, for "read". + self.send(AirInteraction::new(prev_values, do_check.clone(), InteractionKind::Memory)); + + // The current values get "received", i.e. multiplicity = -1 + self.receive(AirInteraction::new( + current_values, + do_check.clone(), + InteractionKind::Memory, + )); + } + + /// Constraints a memory read or write to a slice of `MemoryAccessCols`. + fn eval_memory_access_slice + Copy>( + &mut self, + shard: impl Into + Copy, + channel: impl Into + Clone, + clk: impl Into + Clone, + initial_addr: impl Into + Clone, + memory_access_slice: &[impl MemoryCols], + verify_memory_access: impl Into + Copy, + ) { + for (i, access_slice) in memory_access_slice.iter().enumerate() { + self.eval_memory_access( + shard, + channel.clone(), + clk.clone(), + initial_addr.clone().into() + Self::Expr::from_canonical_usize(i * 4), + access_slice, + verify_memory_access, + ); + } + } + + /// Verifies the memory access timestamp. + /// + /// This method verifies that the current memory access happened after the previous one's. + /// Specifically it will ensure that if the current and previous access are in the same shard, + /// then the current's clk val is greater than the previous's. If they are not in the same + /// shard, then it will ensure that the current's shard val is greater than the previous's. + fn eval_memory_access_timestamp( + &mut self, + mem_access: &MemoryAccessCols + Clone>, + do_check: impl Into, + shard: impl Into + Clone, + channel: impl Into + Clone, + clk: impl Into, + ) { + let do_check: Self::Expr = do_check.into(); + let compare_clk: Self::Expr = mem_access.compare_clk.clone().into(); + let shard: Self::Expr = shard.clone().into(); + let prev_shard: Self::Expr = mem_access.prev_shard.clone().into(); + + // First verify that compare_clk's value is correct. + self.when(do_check.clone()).assert_bool(compare_clk.clone()); + self.when(do_check.clone()).when(compare_clk.clone()).assert_eq(shard.clone(), prev_shard); + + // Get the comparison timestamp values for the current and previous memory access. + let prev_comp_value = self.if_else( + mem_access.compare_clk.clone(), + mem_access.prev_clk.clone(), + mem_access.prev_shard.clone(), + ); + + let current_comp_val = self.if_else(compare_clk.clone(), clk.into(), shard.clone()); + + // Assert `current_comp_val > prev_comp_val`. We check this by asserting that + // `0 <= current_comp_val-prev_comp_val-1 < 2^24`. + // + // The equivalence of these statements comes from the fact that if + // `current_comp_val <= prev_comp_val`, then `current_comp_val-prev_comp_val-1 < 0` and will + // underflow in the prime field, resulting in a value that is `>= 2^24` as long as both + // `current_comp_val, prev_comp_val` are range-checked to be `<2^24` and as long as we're + // working in a field larger than `2 * 2^24` (which is true of the BabyBear and Mersenne31 + // prime). + let diff_minus_one = current_comp_val - prev_comp_value - Self::Expr::one(); + + // Verify that mem_access.ts_diff = mem_access.ts_diff_16bit_limb + // + mem_access.ts_diff_8bit_limb * 2^16. + self.eval_range_check_24bits( + diff_minus_one, + mem_access.diff_16bit_limb.clone(), + mem_access.diff_8bit_limb.clone(), + shard.clone(), + channel.clone(), + do_check, + ); + } + + /// Verifies the inputted value is within 24 bits. + /// + /// This method verifies that the inputted is less than 2^24 by doing a 16 bit and 8 bit range + /// check on it's limbs. It will also verify that the limbs are correct. This method is needed + /// since the memory access timestamp check (see [Self::verify_mem_access_ts]) needs to assume + /// the clk is within 24 bits. + fn eval_range_check_24bits( + &mut self, + value: impl Into, + limb_16: impl Into + Clone, + limb_8: impl Into + Clone, + shard: impl Into + Clone, + channel: impl Into + Clone, + do_check: impl Into + Clone, + ) { + // Verify that value = limb_16 + limb_8 * 2^16. + self.when(do_check.clone()).assert_eq( + value, + limb_16.clone().into() + + limb_8.clone().into() * Self::Expr::from_canonical_u32(1 << 16), + ); + + // Send the range checks for the limbs. + self.send_byte( + Self::Expr::from_canonical_u8(ByteOpcode::U16Range as u8), + limb_16, + Self::Expr::zero(), + Self::Expr::zero(), + shard.clone(), + channel.clone(), + do_check.clone(), + ); + + self.send_byte( + Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), + Self::Expr::zero(), + Self::Expr::zero(), + limb_8, + shard.clone(), + channel.clone(), + do_check, + ) + } +} diff --git a/crates/core/machine/src/air/mod.rs b/crates/core/machine/src/air/mod.rs new file mode 100644 index 0000000000..0f1719c1e3 --- /dev/null +++ b/crates/core/machine/src/air/mod.rs @@ -0,0 +1,21 @@ +mod memory; +mod program; +mod word; + +pub use memory::*; +pub use program::*; +pub use word::*; + +use sp1_stark::air::{BaseAirBuilder, SP1AirBuilder}; + +/// A trait which contains methods related to memory interactions in an AIR. + +pub trait SP1CoreAirBuilder: + SP1AirBuilder + WordAirBuilder + MemoryAirBuilder + ProgramAirBuilder +{ +} + +impl MemoryAirBuilder for AB {} +impl ProgramAirBuilder for AB {} +impl WordAirBuilder for AB {} +impl SP1CoreAirBuilder for AB {} diff --git a/crates/core/machine/src/air/program.rs b/crates/core/machine/src/air/program.rs new file mode 100644 index 0000000000..d94f006d1b --- /dev/null +++ b/crates/core/machine/src/air/program.rs @@ -0,0 +1,50 @@ +use std::iter::once; + +use p3_air::AirBuilder; +use sp1_stark::{ + air::{AirInteraction, BaseAirBuilder}, + InteractionKind, +}; + +use crate::cpu::columns::{InstructionCols, OpcodeSelectorCols}; + +/// A trait which contains methods related to program interactions in an AIR. +pub trait ProgramAirBuilder: BaseAirBuilder { + /// Sends an instruction. + fn send_program( + &mut self, + pc: impl Into, + instruction: InstructionCols + Copy>, + selectors: OpcodeSelectorCols + Copy>, + shard: impl Into + Copy, + multiplicity: impl Into, + ) { + let values = once(pc.into()) + .chain(once(instruction.opcode.into())) + .chain(instruction.into_iter().map(|x| x.into())) + .chain(selectors.into_iter().map(|x| x.into())) + .chain(once(shard.into())) + .collect(); + + self.send(AirInteraction::new(values, multiplicity.into(), InteractionKind::Program)); + } + + /// Receives an instruction. + fn receive_program( + &mut self, + pc: impl Into, + instruction: InstructionCols + Copy>, + selectors: OpcodeSelectorCols + Copy>, + shard: impl Into + Copy, + multiplicity: impl Into, + ) { + let values: Vec<::Expr> = once(pc.into()) + .chain(once(instruction.opcode.into())) + .chain(instruction.into_iter().map(|x| x.into())) + .chain(selectors.into_iter().map(|x| x.into())) + .chain(once(shard.into())) + .collect(); + + self.receive(AirInteraction::new(values, multiplicity.into(), InteractionKind::Program)); + } +} diff --git a/crates/core/machine/src/air/word.rs b/crates/core/machine/src/air/word.rs new file mode 100644 index 0000000000..d96a1c6d31 --- /dev/null +++ b/crates/core/machine/src/air/word.rs @@ -0,0 +1,108 @@ +use std::array; + +use itertools::Itertools; +use p3_field::AbstractField; +use sp1_core_executor::ByteOpcode; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::ByteAirBuilder, Word}; + +pub trait WordAirBuilder: ByteAirBuilder { + /// Asserts that the two words are equal. + fn assert_word_eq( + &mut self, + left: Word>, + right: Word>, + ) { + for (left, right) in left.0.into_iter().zip(right.0) { + self.assert_eq(left, right); + } + } + + /// Asserts that the word is zero. + fn assert_word_zero(&mut self, word: Word>) { + for limb in word.0 { + self.assert_zero(limb); + } + } + + /// Index an array of words using an index bitmap. + fn index_word_array( + &mut self, + array: &[Word + Clone>], + index_bitmap: &[impl Into + Clone], + ) -> Word { + let mut result = Word::default(); + for i in 0..WORD_SIZE { + result[i] = self.index_array( + array.iter().map(|word| word[i].clone()).collect_vec().as_slice(), + index_bitmap, + ); + } + result + } + + /// Same as `if_else` above, but arguments are `Word` instead of individual expressions. + fn select_word( + &mut self, + condition: impl Into + Clone, + a: Word + Clone>, + b: Word + Clone>, + ) -> Word { + Word(array::from_fn(|i| self.if_else(condition.clone(), a[i].clone(), b[i].clone()))) + } + + /// Check that each limb of the given slice is a u8. + fn slice_range_check_u8( + &mut self, + input: &[impl Into + Clone], + shard: impl Into + Clone, + channel: impl Into + Clone, + mult: impl Into + Clone, + ) { + let mut index = 0; + while index + 1 < input.len() { + self.send_byte( + Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), + Self::Expr::zero(), + input[index].clone(), + input[index + 1].clone(), + shard.clone(), + channel.clone(), + mult.clone(), + ); + index += 2; + } + if index < input.len() { + self.send_byte( + Self::Expr::from_canonical_u8(ByteOpcode::U8Range as u8), + Self::Expr::zero(), + input[index].clone(), + Self::Expr::zero(), + shard.clone(), + channel.clone(), + mult.clone(), + ); + } + } + + /// Check that each limb of the given slice is a u16. + fn slice_range_check_u16( + &mut self, + input: &[impl Into + Copy], + shard: impl Into + Clone, + channel: impl Into + Clone, + mult: impl Into + Clone, + ) { + input.iter().for_each(|limb| { + self.send_byte( + Self::Expr::from_canonical_u8(ByteOpcode::U16Range as u8), + *limb, + Self::Expr::zero(), + Self::Expr::zero(), + shard.clone(), + channel.clone(), + mult.clone(), + ); + }); + } +} diff --git a/core/src/alu/add_sub/mod.rs b/crates/core/machine/src/alu/add_sub/mod.rs similarity index 83% rename from core/src/alu/add_sub/mod.rs rename to crates/core/machine/src/alu/add_sub/mod.rs index b1eb2d1f9f..ee8efafb03 100644 --- a/core/src/alu/add_sub/mod.rs +++ b/crates/core/machine/src/alu/add_sub/mod.rs @@ -1,25 +1,25 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use itertools::Itertools; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_maybe_rayon::prelude::ParallelSlice; -use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{AluEvent, ByteLookupEvent, ByteRecord}, + ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::{ + air::{MachineAir, SP1AirBuilder}, + Word, +}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::operations::AddOperation; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::utils::pad_to_power_of_two; - -use super::AluEvent; +use crate::{operations::AddOperation, utils::pad_to_power_of_two}; /// The number of main trace columns for `AddSubChip`. pub const NUM_ADD_SUB_COLS: usize = size_of::>(); @@ -78,15 +78,10 @@ impl MachineAir for AddSubChip { _: &mut ExecutionRecord, ) -> RowMajorMatrix { // Generate the rows for the trace. - let chunk_size = std::cmp::max( - (input.add_events.len() + input.sub_events.len()) / num_cpus::get(), - 1, - ); - let merged_events = input - .add_events - .iter() - .chain(input.sub_events.iter()) - .collect::>(); + let chunk_size = + std::cmp::max((input.add_events.len() + input.sub_events.len()) / num_cpus::get(), 1); + let merged_events = + input.add_events.iter().chain(input.sub_events.iter()).collect::>(); let row_batches = merged_events .par_chunks(chunk_size) @@ -111,10 +106,8 @@ impl MachineAir for AddSubChip { } // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_ADD_SUB_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_ADD_SUB_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); @@ -130,15 +123,11 @@ impl MachineAir for AddSubChip { } fn generate_dependencies(&self, input: &Self::Record, output: &mut Self::Record) { - let chunk_size = std::cmp::max( - (input.add_events.len() + input.sub_events.len()) / num_cpus::get(), - 1, - ); + let chunk_size = + std::cmp::max((input.add_events.len() + input.sub_events.len()) / num_cpus::get(), 1); - let event_iter = input - .add_events - .chunks(chunk_size) - .chain(input.sub_events.chunks(chunk_size)); + let event_iter = + input.add_events.chunks(chunk_size).chain(input.sub_events.chunks(chunk_size)); let blu_batches = event_iter .par_bridge() @@ -178,8 +167,7 @@ impl AddSubChip { let operand_1 = if is_add { event.b } else { event.a }; let operand_2 = event.c; - cols.add_operation - .populate(blu, event.shard, event.channel, operand_1, operand_2); + cols.add_operation.populate(blu, event.shard, event.channel, operand_1, operand_2); cols.operand_1 = Word::from(operand_1); cols.operand_2 = Word::from(operand_2); } @@ -204,9 +192,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // Evaluate the addition operation. AddOperation::::eval( @@ -255,20 +241,12 @@ where mod tests { use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; use rand::{thread_rng, Rng}; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::AddSubChip; - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; #[test] fn generate_trace() { diff --git a/core/src/alu/bitwise/mod.rs b/crates/core/machine/src/alu/bitwise/mod.rs similarity index 84% rename from core/src/alu/bitwise/mod.rs rename to crates/core/machine/src/alu/bitwise/mod.rs index 5c35df0b14..556bd22dcc 100644 --- a/core/src/alu/bitwise/mod.rs +++ b/crates/core/machine/src/alu/bitwise/mod.rs @@ -1,25 +1,26 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use itertools::Itertools; -use p3_air::AirBuilder; -use p3_air::{Air, BaseAir}; +use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{IntoParallelRefIterator, ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{AluEvent, ByteLookupEvent, ByteRecord}, + ByteOpcode, ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::{ + air::{MachineAir, SP1AirBuilder}, + Word, +}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::runtime::{ExecutionRecord, Opcode, Program}; use crate::utils::pad_to_power_of_two; -use super::AluEvent; - /// The number of main trace columns for `BitwiseChip`. pub const NUM_BITWISE_COLS: usize = size_of::>(); @@ -86,10 +87,8 @@ impl MachineAir for BitwiseChip { .collect::>(); // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_BITWISE_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_BITWISE_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); @@ -184,9 +183,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // Get the opcode for the operation. let opcode = local.is_xor * ByteOpcode::XOR.as_field::() @@ -196,15 +193,7 @@ where // Get a multiplicity of `1` only for a true row. let mult = local.is_xor + local.is_or + local.is_and; for ((a, b), c) in local.a.into_iter().zip(local.b).zip(local.c) { - builder.send_byte( - opcode.clone(), - a, - b, - c, - local.shard, - local.channel, - mult.clone(), - ); + builder.send_byte(opcode.clone(), a, b, c, local.shard, local.channel, mult.clone()); } // Get the cpu opcode, which corresponds to the opcode being sent in the CPU table. @@ -236,15 +225,12 @@ where mod tests { use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; - use crate::air::MachineAir; - use crate::stark::StarkGenericConfig; - use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; + use crate::utils::{uni_stark_prove, uni_stark_verify}; use super::BitwiseChip; - use crate::alu::AluEvent; - use crate::runtime::{ExecutionRecord, Opcode}; - use crate::utils::BabyBearPoseidon2; #[test] fn generate_trace() { @@ -271,9 +257,9 @@ mod tests { let chip = BitwiseChip::default(); let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); - let proof = prove::(&config, &chip, &mut challenger, trace); + let proof = uni_stark_prove::(&config, &chip, &mut challenger, trace); let mut challenger = config.challenger(); - verify(&config, &chip, &mut challenger, &proof).unwrap(); + uni_stark_verify(&config, &chip, &mut challenger, &proof).unwrap(); } } diff --git a/core/src/alu/divrem/mod.rs b/crates/core/machine/src/alu/divrem/mod.rs similarity index 91% rename from core/src/alu/divrem/mod.rs rename to crates/core/machine/src/alu/divrem/mod.rs index 673c10a6cd..9beb1ddf13 100644 --- a/core/src/alu/divrem/mod.rs +++ b/crates/core/machine/src/alu/divrem/mod.rs @@ -62,27 +62,29 @@ mod utils; -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, PrimeField}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{create_alu_lookups, AluEvent, ByteLookupEvent, ByteRecord}, + ByteOpcode, ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::MachineAir, Word}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::alu::divrem::utils::{get_msb, get_quotient_and_remainder, is_signed_operation}; -use crate::alu::{create_alu_lookups, AluEvent}; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::disassembler::WORD_SIZE; -use crate::operations::{IsEqualWordOperation, IsZeroWordOperation}; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::utils::pad_to_power_of_two; +use crate::{ + air::SP1CoreAirBuilder, + alu::divrem::utils::{get_msb, get_quotient_and_remainder, is_signed_operation}, + operations::{IsEqualWordOperation, IsZeroWordOperation}, + utils::pad_to_power_of_two, +}; /// The number of main trace columns for `DivRemChip`. pub const NUM_DIVREM_COLS: usize = size_of::>(); @@ -158,15 +160,17 @@ pub struct DivRemCols { /// Flag to indicate whether the division operation overflows. /// /// Overflow occurs in a specific case of signed 32-bit integer division: when `b` is the - /// minimum representable value (`-2^31`, the smallest negative number) and `c` is `-1`. In this - /// case, the division result exceeds the maximum positive value representable by a 32-bit - /// signed integer. + /// minimum representable value (`-2^31`, the smallest negative number) and `c` is `-1`. In + /// this case, the division result exceeds the maximum positive value representable by a + /// 32-bit signed integer. pub is_overflow: T, - /// Flag for whether the value of `b` matches the unique overflow case `b = -2^31` and `c = -1`. + /// Flag for whether the value of `b` matches the unique overflow case `b = -2^31` and `c = + /// -1`. pub is_overflow_b: IsEqualWordOperation, - /// Flag for whether the value of `c` matches the unique overflow case `b = -2^31` and `c = -1`. + /// Flag for whether the value of `c` matches the unique overflow case `b = -2^31` and `c = + /// -1`. pub is_overflow_c: IsEqualWordOperation, /// The most significant bit of `b`. @@ -282,19 +286,11 @@ impl MachineAir for DivRemChip { // Set the `alu_event` flags. cols.abs_c_alu_event = cols.c_neg * cols.is_real; cols.abs_c_alu_event_nonce = F::from_canonical_u32( - input - .nonce_lookup - .get(&event.sub_lookups[4]) - .copied() - .unwrap_or_default(), + input.nonce_lookup.get(&event.sub_lookups[4]).copied().unwrap_or_default(), ); cols.abs_rem_alu_event = cols.rem_neg * cols.is_real; cols.abs_rem_alu_event_nonce = F::from_canonical_u32( - input - .nonce_lookup - .get(&event.sub_lookups[5]) - .copied() - .unwrap_or_default(), + input.nonce_lookup.get(&event.sub_lookups[5]).copied().unwrap_or_default(), ); // Insert the MSB lookup events. @@ -415,11 +411,7 @@ impl MachineAir for DivRemChip { sub_lookups: create_alu_lookups(), }; cols.lower_nonce = F::from_canonical_u32( - input - .nonce_lookup - .get(&event.sub_lookups[0]) - .copied() - .unwrap_or_default(), + input.nonce_lookup.get(&event.sub_lookups[0]).copied().unwrap_or_default(), ); output.add_mul_event(lower_multiplication); @@ -441,11 +433,7 @@ impl MachineAir for DivRemChip { sub_lookups: create_alu_lookups(), }; cols.upper_nonce = F::from_canonical_u32( - input - .nonce_lookup - .get(&event.sub_lookups[1]) - .copied() - .unwrap_or_default(), + input.nonce_lookup.get(&event.sub_lookups[1]).copied().unwrap_or_default(), ); output.add_mul_event(upper_multiplication); let lt_event = if is_signed_operation(event.opcode) { @@ -509,10 +497,8 @@ impl MachineAir for DivRemChip { } // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_DIVREM_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_DIVREM_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); @@ -560,7 +546,7 @@ impl BaseAir for DivRemChip { impl Air for DivRemChip where - AB: SP1AirBuilder, + AB: SP1CoreAirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); @@ -574,9 +560,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // Calculate whether b, remainder, and c are negative. { @@ -706,13 +690,10 @@ where // - All 1s (0xff) for negative b. // - All 0s for non-negative b. let not_overflow = one.clone() - local.is_overflow; - builder - .when(not_overflow.clone()) - .when(local.b_neg) - .assert_eq( - c_times_quotient_plus_remainder[i].clone(), - AB::F::from_canonical_u8(u8::MAX), - ); + builder.when(not_overflow.clone()).when(local.b_neg).assert_eq( + c_times_quotient_plus_remainder[i].clone(), + AB::F::from_canonical_u8(u8::MAX), + ); builder .when(not_overflow.clone()) .when_ne(one.clone(), local.b_neg) @@ -728,12 +709,8 @@ where // a must equal remainder or quotient depending on the opcode. for i in 0..WORD_SIZE { - builder - .when(local.is_divu + local.is_div) - .assert_eq(local.quotient[i], local.a[i]); - builder - .when(local.is_remu + local.is_rem) - .assert_eq(local.remainder[i], local.a[i]); + builder.when(local.is_divu + local.is_div).assert_eq(local.quotient[i], local.a[i]); + builder.when(local.is_remu + local.is_rem).assert_eq(local.remainder[i], local.a[i]); } // remainder and b must have the same sign. Due to the intricate nature of sign logic in ZK, @@ -783,12 +760,10 @@ where // Range check remainder. (i.e., |remainder| < |c| when not is_c_0) { - // For each of `c` and `rem`, assert that the absolute value is equal to the original value, - // if the original value is non-negative or the minimum i32. + // For each of `c` and `rem`, assert that the absolute value is equal to the original + // value, if the original value is non-negative or the minimum i32. for i in 0..WORD_SIZE { - builder - .when_not(local.c_neg) - .assert_eq(local.c[i], local.abs_c[i]); + builder.when_not(local.c_neg).assert_eq(local.c[i], local.abs_c[i]); builder .when_not(local.rem_neg) .assert_eq(local.remainder[i], local.abs_remainder[i]); @@ -843,7 +818,8 @@ where local.remainder_check_multiplicity, ); - // the cleaner idea is simply remainder_check_multiplicity == (1 - is_c_0_result) * is_real + // the cleaner idea is simply remainder_check_multiplicity == (1 - is_c_0_result) * + // is_real // Check that the absolute value selector columns are computed correctly. builder.assert_eq(local.abs_c_alu_event, local.c_neg * local.is_real); @@ -974,19 +950,11 @@ where #[cfg(test)] mod tests { - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; + use crate::utils::{uni_stark_prove, uni_stark_verify}; use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::DivRemChip; @@ -1059,9 +1027,9 @@ mod tests { let chip = DivRemChip::default(); let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); - let proof = prove::(&config, &chip, &mut challenger, trace); + let proof = uni_stark_prove::(&config, &chip, &mut challenger, trace); let mut challenger = config.challenger(); - verify(&config, &chip, &mut challenger, &proof).unwrap(); + uni_stark_verify(&config, &chip, &mut challenger, &proof).unwrap(); } } diff --git a/core/src/alu/divrem/utils.rs b/crates/core/machine/src/alu/divrem/utils.rs similarity index 72% rename from core/src/alu/divrem/utils.rs rename to crates/core/machine/src/alu/divrem/utils.rs index d71c35aad6..5147d20f6c 100644 --- a/core/src/alu/divrem/utils.rs +++ b/crates/core/machine/src/alu/divrem/utils.rs @@ -1,4 +1,4 @@ -use crate::runtime::Opcode; +use sp1_core_executor::Opcode; /// Returns `true` if the given `opcode` is a signed operation. pub fn is_signed_operation(opcode: Opcode) -> bool { @@ -12,15 +12,9 @@ pub fn get_quotient_and_remainder(b: u32, c: u32, opcode: Opcode) -> (u32, u32) // perform signed or unsigned division. (u32::MAX, b) } else if is_signed_operation(opcode) { - ( - (b as i32).wrapping_div(c as i32) as u32, - (b as i32).wrapping_rem(c as i32) as u32, - ) + ((b as i32).wrapping_div(c as i32) as u32, (b as i32).wrapping_rem(c as i32) as u32) } else { - ( - (b as u32).wrapping_div(c as u32) as u32, - (b as u32).wrapping_rem(c as u32) as u32, - ) + ((b as u32).wrapping_div(c as u32) as u32, (b as u32).wrapping_rem(c as u32) as u32) } } diff --git a/core/src/alu/lt/mod.rs b/crates/core/machine/src/alu/lt/mod.rs similarity index 89% rename from core/src/alu/lt/mod.rs rename to crates/core/machine/src/alu/lt/mod.rs index 97674d5268..1ae8b47893 100644 --- a/core/src/alu/lt/mod.rs +++ b/crates/core/machine/src/alu/lt/mod.rs @@ -1,25 +1,26 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use itertools::{izip, Itertools}; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::Field; -use p3_field::{AbstractField, PrimeField32}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, Field, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::*; +use sp1_core_executor::{ + events::{AluEvent, ByteLookupEvent, ByteRecord}, + ByteOpcode, ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::{ + air::{BaseAirBuilder, MachineAir, SP1AirBuilder}, + Word, +}; -use crate::air::{BaseAirBuilder, MachineAir}; -use crate::air::{SP1AirBuilder, Word}; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::runtime::{ExecutionRecord, Opcode, Program}; use crate::utils::pad_to_power_of_two; -use super::AluEvent; - /// The number of main trace columns for `LtChip`. pub const NUM_LT_COLS: usize = size_of::>(); @@ -88,12 +89,8 @@ pub struct LtCols { impl LtCols { pub fn from_trace_row(row: &[F]) -> Self { - let sized: [u32; NUM_LT_COLS] = row - .iter() - .map(|x| x.as_canonical_u32()) - .collect::>() - .try_into() - .unwrap(); + let sized: [u32; NUM_LT_COLS] = + row.iter().map(|x| x.as_canonical_u32()).collect::>().try_into().unwrap(); *sized.as_slice().borrow() } } @@ -222,11 +219,9 @@ impl LtChip { cols.is_comp_eq = F::from_bool(b_comp == c_comp); // Set the byte equality flags. - for (b_byte, c_byte, flag) in izip!( - b_comp.iter().rev(), - c_comp.iter().rev(), - cols.byte_flags.iter_mut().rev() - ) { + for (b_byte, c_byte, flag) in + izip!(b_comp.iter().rev(), c_comp.iter().rev(), cols.byte_flags.iter_mut().rev()) + { if c_byte != b_byte { *flag = F::one(); cols.sltu = F::from_bool(b_byte < c_byte); @@ -252,10 +247,7 @@ impl LtChip { cols.bit_b = cols.msb_b * cols.is_slt; cols.bit_c = cols.msb_c * cols.is_slt; - assert_eq!( - cols.a[0], - cols.bit_b * (F::one() - cols.bit_c) + cols.is_sign_eq * cols.sltu - ); + assert_eq!(cols.a[0], cols.bit_b * (F::one() - cols.bit_c) + cols.is_sign_eq * cols.sltu); blu.add_byte_lookup_event(ByteLookupEvent { shard: event.shard, @@ -288,9 +280,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let is_real = local.is_slt + local.is_sltu; @@ -354,9 +344,7 @@ where builder.assert_bool(local.is_sign_eq); // assert the correction of the comparison. - builder - .when(local.is_sign_eq) - .assert_eq(local.bit_b, local.bit_c); + builder.when(local.is_sign_eq).assert_eq(local.bit_b, local.bit_c); builder .when(is_real.clone()) .when_not(local.is_sign_eq) @@ -383,9 +371,7 @@ where builder.assert_bool(local.byte_flags[2]); builder.assert_bool(local.byte_flags[3]); builder.assert_bool(sum_flags.clone()); - builder - .when(is_real.clone()) - .assert_eq(AB::Expr::one() - local.is_comp_eq, sum_flags); + builder.when(is_real.clone()).assert_eq(AB::Expr::one() - local.is_comp_eq, sum_flags); // Constrain `local.sltu == STLU(b_comp, c_comp)`. // @@ -409,11 +395,9 @@ where let mut c_comparison_byte = AB::Expr::zero(); // Iterate over the bytes in reverse order and select the differing bytes using the byte // flag columns values. - for (b_byte, c_byte, &flag) in izip!( - b_comp.0.iter().rev(), - c_comp.0.iter().rev(), - local.byte_flags.iter().rev() - ) { + for (b_byte, c_byte, &flag) in + izip!(b_comp.0.iter().rev(), c_comp.0.iter().rev(), local.byte_flags.iter().rev()) + { // Once the byte flag was set to one, we turn off the quality check flag. // We can do this by calculating the sum of the flags since only `1` is set to `1`. is_inequality_visited += flag.into(); @@ -426,9 +410,7 @@ where .when_not(is_inequality_visited.clone()) .assert_eq(b_byte.clone(), c_byte.clone()); // If the numbers are assumed equal, inequality should not be visited. - builder - .when(local.is_comp_eq) - .assert_zero(is_inequality_visited.clone()); + builder.when(local.is_comp_eq).assert_zero(is_inequality_visited.clone()); } // We need to verify that the comparison bytes are set correctly. This is only relevant in // the case where the bytes are not equal. @@ -442,10 +424,9 @@ where // in the loop that when `local.is_comp_eq == 1` then all bytes are euqal. It is left to // verify that when `local.is_comp_eq == 0` the comparison bytes are indeed not equal. // This is done using the inverse hint `not_eq_inv`. - builder.when_not(local.is_comp_eq).assert_eq( - local.not_eq_inv * (b_comp_byte - c_comp_byte), - is_real.clone(), - ); + builder + .when_not(local.is_comp_eq) + .assert_eq(local.not_eq_inv * (b_comp_byte - c_comp_byte), is_real.clone()); // Now the value of `local.sltu` is equal to the same value for the comparison bytes. // @@ -489,19 +470,11 @@ where #[cfg(test)] mod tests { - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; + use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::LtChip; @@ -510,8 +483,8 @@ mod tests { let mut shard = ExecutionRecord::default(); shard.lt_events = vec![AluEvent::new(0, 1, 0, Opcode::SLT, 0, 3, 2)]; let chip = LtChip::default(); - let trace: RowMajorMatrix = - chip.generate_trace(&shard, &mut ExecutionRecord::default()); + let generate_trace = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + let trace: RowMajorMatrix = generate_trace; println!("{:?}", trace.values) } diff --git a/crates/core/machine/src/alu/mod.rs b/crates/core/machine/src/alu/mod.rs new file mode 100644 index 0000000000..f2e3f88b7e --- /dev/null +++ b/crates/core/machine/src/alu/mod.rs @@ -0,0 +1,15 @@ +pub mod add_sub; +pub mod bitwise; +pub mod divrem; +pub mod lt; +pub mod mul; +pub mod sll; +pub mod sr; + +pub use add_sub::*; +pub use bitwise::*; +pub use divrem::*; +pub use lt::*; +pub use mul::*; +pub use sll::*; +pub use sr::*; diff --git a/core/src/alu/mul/mod.rs b/crates/core/machine/src/alu/mul/mod.rs similarity index 92% rename from core/src/alu/mul/mod.rs rename to crates/core/machine/src/alu/mul/mod.rs index dd7d27de56..98dbc7a80e 100644 --- a/core/src/alu/mul/mod.rs +++ b/crates/core/machine/src/alu/mul/mod.rs @@ -30,27 +30,24 @@ mod utils; -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSlice; +use p3_field::{AbstractField, PrimeField}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::MachineAir, MachineRecord, Word}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::alu::mul::utils::get_msb; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::disassembler::WORD_SIZE; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::stark::MachineRecord; -use crate::utils::pad_to_power_of_two; +use crate::{air::SP1CoreAirBuilder, alu::mul::utils::get_msb, utils::pad_to_power_of_two}; /// The number of main trace columns for `MulChip`. pub const NUM_MUL_COLS: usize = size_of::>(); @@ -218,8 +215,8 @@ impl MachineAir for MulChip { } } - // Calculate the correct product using the `product` array. We store the correct carry - // value for verification. + // Calculate the correct product using the `product` array. We store the + // correct carry value for verification. let base = (1 << BYTE_SIZE) as u32; let mut carry = [0u32; PRODUCT_SIZE]; for i in 0..PRODUCT_SIZE { @@ -300,7 +297,7 @@ impl BaseAir for MulChip { impl Air for MulChip where - AB: SP1AirBuilder, + AB: SP1CoreAirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); @@ -316,16 +313,12 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // Calculate the MSBs. let (b_msb, c_msb) = { - let msb_pairs = [ - (local.b_msb, local.b[WORD_SIZE - 1]), - (local.c_msb, local.c[WORD_SIZE - 1]), - ]; + let msb_pairs = + [(local.b_msb, local.b[WORD_SIZE - 1]), (local.c_msb, local.c[WORD_SIZE - 1])]; let opcode = AB::F::from_canonical_u32(ByteOpcode::MSB as u32); for msb_pair in msb_pairs.iter() { let msb = msb_pair.0; @@ -402,9 +395,7 @@ where let is_upper = local.is_mulh + local.is_mulhu + local.is_mulhsu; for i in 0..WORD_SIZE { builder.when(is_lower).assert_eq(product[i], local.a[i]); - builder - .when(is_upper.clone()) - .assert_eq(product[i + WORD_SIZE], local.a[i]); + builder.when(is_upper.clone()).assert_eq(product[i + WORD_SIZE], local.a[i]); } } @@ -427,12 +418,8 @@ where } // If signed extended, the MSB better be 1. - builder - .when(local.b_sign_extend) - .assert_eq(local.b_msb, one.clone()); - builder - .when(local.c_sign_extend) - .assert_eq(local.c_msb, one.clone()); + builder.when(local.b_sign_extend).assert_eq(local.b_msb, one.clone()); + builder.when(local.c_sign_extend).assert_eq(local.c_msb, one.clone()); // Calculate the opcode. let opcode = { @@ -478,19 +465,11 @@ where #[cfg(test)] mod tests { - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; + use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::MulChip; diff --git a/core/src/alu/mul/utils.rs b/crates/core/machine/src/alu/mul/utils.rs similarity index 75% rename from core/src/alu/mul/utils.rs rename to crates/core/machine/src/alu/mul/utils.rs index db2914aca7..85b389d57d 100644 --- a/core/src/alu/mul/utils.rs +++ b/crates/core/machine/src/alu/mul/utils.rs @@ -1,4 +1,4 @@ -use crate::air::WORD_SIZE; +use sp1_primitives::consts::WORD_SIZE; use super::BYTE_SIZE; diff --git a/core/src/alu/sll/mod.rs b/crates/core/machine/src/alu/sll/mod.rs similarity index 92% rename from core/src/alu/sll/mod.rs rename to crates/core/machine/src/alu/sll/mod.rs index d40da149a0..50b3694073 100644 --- a/core/src/alu/sll/mod.rs +++ b/crates/core/machine/src/alu/sll/mod.rs @@ -30,27 +30,26 @@ //! - Ideally, we would calculate b * pow(2, c), but pow(2, c) could overflow in F. //! - Shifting by a multiple of 8 bits is easy (=num_bytes_to_shift) since we just shift words. -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use itertools::Itertools; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{AluEvent, ByteLookupEvent, ByteRecord}, + ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::MachineAir, Word}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::disassembler::WORD_SIZE; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::utils::pad_to_power_of_two; - -use super::AluEvent; +use crate::{air::SP1CoreAirBuilder, utils::pad_to_power_of_two}; /// The number of main trace columns for `ShiftLeft`. pub const NUM_SHIFT_LEFT_COLS: usize = size_of::>(); @@ -261,7 +260,7 @@ impl BaseAir for ShiftLeft { impl Air for ShiftLeft where - AB: SP1AirBuilder, + AB: SP1CoreAirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); @@ -276,9 +275,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // We first "bit shift" and next we "byte shift". Then we compare the results with a. // Finally, we perform some misc checks. @@ -309,10 +306,9 @@ where // Check bit_shift_multiplier = 2^num_bits_to_shift by using shift_by_n_bits. for i in 0..BYTE_SIZE { - builder.when(local.shift_by_n_bits[i]).assert_eq( - local.bit_shift_multiplier, - AB::F::from_canonical_usize(1 << i), - ); + builder + .when(local.shift_by_n_bits[i]) + .assert_eq(local.bit_shift_multiplier, AB::F::from_canonical_usize(1 << i)); } // Check bit_shift_result = b * bit_shift_multiplier by using bit_shift_result_carry to @@ -363,10 +359,7 @@ where builder.assert_bool(*shift); } builder.assert_eq( - local - .shift_by_n_bits - .iter() - .fold(zero.clone(), |acc, &x| acc + x), + local.shift_by_n_bits.iter().fold(zero.clone(), |acc, &x| acc + x), one.clone(), ); @@ -391,10 +384,7 @@ where } builder.assert_eq( - local - .shift_by_n_bytes - .iter() - .fold(zero.clone(), |acc, &x| acc + x), + local.shift_by_n_bytes.iter().fold(zero.clone(), |acc, &x| acc + x), one.clone(), ); @@ -417,19 +407,11 @@ where #[cfg(test)] mod tests { - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; + use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::ShiftLeft; diff --git a/core/src/alu/sr/mod.rs b/crates/core/machine/src/alu/sr/mod.rs similarity index 93% rename from core/src/alu/sr/mod.rs rename to crates/core/machine/src/alu/sr/mod.rs index a905e717fc..88ca2eacd4 100644 --- a/core/src/alu/sr/mod.rs +++ b/crates/core/machine/src/alu/sr/mod.rs @@ -43,29 +43,30 @@ mod utils; -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use hashbrown::HashMap; use itertools::Itertools; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, PrimeField}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{AluEvent, ByteLookupEvent, ByteRecord}, + ByteOpcode, ExecutionRecord, Opcode, Program, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::MachineAir, Word}; -use crate::air::MachineAir; -use crate::air::{SP1AirBuilder, Word}; -use crate::alu::sr::utils::{nb_bits_to_shift, nb_bytes_to_shift}; -use crate::bytes::event::ByteRecord; -use crate::bytes::utils::shr_carry; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::disassembler::WORD_SIZE; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::utils::pad_to_power_of_two; - -use super::AluEvent; +use crate::{ + air::SP1CoreAirBuilder, + alu::sr::utils::{nb_bits_to_shift, nb_bytes_to_shift}, + bytes::utils::shr_carry, + utils::pad_to_power_of_two, +}; /// The number of main trace columns for `ShiftRightChip`. pub const NUM_SHIFT_RIGHT_COLS: usize = size_of::>(); @@ -341,7 +342,7 @@ impl BaseAir for ShiftRightChip { impl Air for ShiftRightChip where - AB: SP1AirBuilder, + AB: SP1CoreAirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); @@ -354,9 +355,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // Check that the MSB of most_significant_byte matches local.b_msb using lookup. { @@ -400,10 +399,7 @@ where // Exactly one of the shift_by_n_bits must be 1. builder.assert_eq( - local - .shift_by_n_bits - .iter() - .fold(zero.clone(), |acc, &x| acc + x), + local.shift_by_n_bits.iter().fold(zero.clone(), |acc, &x| acc + x), one.clone(), ); @@ -421,10 +417,7 @@ where // Exactly one of the shift_by_n_bytes must be 1. builder.assert_eq( - local - .shift_by_n_bytes - .iter() - .fold(zero.clone(), |acc, &x| acc + x), + local.shift_by_n_bytes.iter().fold(zero.clone(), |acc, &x| acc + x), one.clone(), ); } @@ -444,12 +437,10 @@ where // Shift the bytes of sign_extended_b by num_bytes_to_shift. for num_bytes_to_shift in 0..WORD_SIZE { for i in 0..(LONG_WORD_SIZE - num_bytes_to_shift) { - builder - .when(local.shift_by_n_bytes[num_bytes_to_shift]) - .assert_eq( - local.byte_shift_result[i], - sign_extended_b[i + num_bytes_to_shift].clone(), - ); + builder.when(local.shift_by_n_bytes[num_bytes_to_shift]).assert_eq( + local.byte_shift_result[i], + sign_extended_b[i + num_bytes_to_shift].clone(), + ); } } } @@ -558,19 +549,11 @@ where #[cfg(test)] mod tests { - use crate::{ - air::MachineAir, - stark::StarkGenericConfig, - utils::{uni_stark_prove as prove, uni_stark_verify as verify}, - }; + use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; - - use crate::{ - alu::AluEvent, - runtime::{ExecutionRecord, Opcode}, - utils::BabyBearPoseidon2, - }; + use sp1_core_executor::{events::AluEvent, ExecutionRecord, Opcode}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::ShiftRightChip; diff --git a/core/src/alu/sr/utils.rs b/crates/core/machine/src/alu/sr/utils.rs similarity index 100% rename from core/src/alu/sr/utils.rs rename to crates/core/machine/src/alu/sr/utils.rs diff --git a/core/src/bytes/air.rs b/crates/core/machine/src/bytes/air.rs similarity index 92% rename from core/src/bytes/air.rs rename to crates/core/machine/src/bytes/air.rs index 7f0bd3f3eb..210783a89e 100644 --- a/core/src/bytes/air.rs +++ b/crates/core/machine/src/bytes/air.rs @@ -1,14 +1,15 @@ use core::borrow::Borrow; -use p3_air::PairBuilder; -use p3_air::{Air, BaseAir}; -use p3_field::AbstractField; -use p3_field::Field; +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::{AbstractField, Field}; use p3_matrix::Matrix; +use sp1_core_executor::ByteOpcode; +use sp1_stark::air::SP1AirBuilder; -use super::columns::{ByteMultCols, BytePreprocessedCols, NUM_BYTE_MULT_COLS}; -use super::{ByteChip, ByteOpcode, NUM_BYTE_LOOKUP_CHANNELS}; -use crate::air::SP1AirBuilder; +use super::{ + columns::{ByteMultCols, BytePreprocessedCols, NUM_BYTE_MULT_COLS}, + ByteChip, NUM_BYTE_LOOKUP_CHANNELS, +}; impl BaseAir for ByteChip { fn width(&self) -> usize { diff --git a/core/src/bytes/columns.rs b/crates/core/machine/src/bytes/columns.rs similarity index 100% rename from core/src/bytes/columns.rs rename to crates/core/machine/src/bytes/columns.rs diff --git a/core/src/bytes/mod.rs b/crates/core/machine/src/bytes/mod.rs similarity index 96% rename from core/src/bytes/mod.rs rename to crates/core/machine/src/bytes/mod.rs index ec87c06987..91e72bf7f2 100644 --- a/core/src/bytes/mod.rs +++ b/crates/core/machine/src/bytes/mod.rs @@ -1,12 +1,11 @@ pub mod air; pub mod columns; -pub mod event; -pub mod opcode; +// pub mod event; +// pub mod opcode; pub mod trace; pub mod utils; -pub use event::ByteLookupEvent; -pub use opcode::*; +use sp1_core_executor::{events::ByteLookupEvent, ByteOpcode}; use core::borrow::BorrowMut; use std::marker::PhantomData; @@ -15,8 +14,10 @@ use itertools::Itertools; use p3_field::Field; use p3_matrix::dense::RowMajorMatrix; -use self::columns::{BytePreprocessedCols, NUM_BYTE_PREPROCESSED_COLS}; -use self::utils::shr_carry; +use self::{ + columns::{BytePreprocessedCols, NUM_BYTE_PREPROCESSED_COLS}, + utils::shr_carry, +}; use crate::bytes::trace::NUM_ROWS; /// The number of different byte operations. diff --git a/core/src/bytes/trace.rs b/crates/core/machine/src/bytes/trace.rs similarity index 80% rename from core/src/bytes/trace.rs rename to crates/core/machine/src/bytes/trace.rs index 3db90683ff..0ea612ca44 100644 --- a/core/src/bytes/trace.rs +++ b/crates/core/machine/src/bytes/trace.rs @@ -3,16 +3,13 @@ use std::borrow::BorrowMut; use hashbrown::HashMap; use p3_field::Field; use p3_matrix::dense::RowMajorMatrix; +use sp1_core_executor::{ByteOpcode, ExecutionRecord, Program}; +use sp1_stark::air::MachineAir; use super::{ columns::{ByteMultCols, NUM_BYTE_MULT_COLS, NUM_BYTE_PREPROCESSED_COLS}, ByteChip, }; -use crate::{ - air::MachineAir, - bytes::ByteOpcode, - runtime::{ExecutionRecord, Program}, -}; pub const NUM_ROWS: usize = 1 << 16; @@ -43,18 +40,11 @@ impl MachineAir for ByteChip { input: &ExecutionRecord, _output: &mut ExecutionRecord, ) -> RowMajorMatrix { - let mut trace = RowMajorMatrix::new( - vec![F::zero(); NUM_BYTE_MULT_COLS * NUM_ROWS], - NUM_BYTE_MULT_COLS, - ); + let mut trace = + RowMajorMatrix::new(vec![F::zero(); NUM_BYTE_MULT_COLS * NUM_ROWS], NUM_BYTE_MULT_COLS); let shard = input.public_values.execution_shard; - for (lookup, mult) in input - .byte_lookups - .get(&shard) - .unwrap_or(&HashMap::new()) - .iter() - { + for (lookup, mult) in input.byte_lookups.get(&shard).unwrap_or(&HashMap::new()).iter() { let row = if lookup.opcode != ByteOpcode::U16Range { (((lookup.b as u16) << 8) + lookup.c as u16) as usize } else { diff --git a/core/src/bytes/utils.rs b/crates/core/machine/src/bytes/utils.rs similarity index 100% rename from core/src/bytes/utils.rs rename to crates/core/machine/src/bytes/utils.rs diff --git a/core/src/cpu/air/branch.rs b/crates/core/machine/src/cpu/air/branch.rs similarity index 87% rename from core/src/cpu/air/branch.rs rename to crates/core/machine/src/cpu/air/branch.rs index 60bba4175e..1377d1a14e 100644 --- a/core/src/cpu/air/branch.rs +++ b/crates/core/machine/src/cpu/air/branch.rs @@ -1,10 +1,20 @@ use p3_air::AirBuilder; use p3_field::AbstractField; - -use crate::air::{BaseAirBuilder, SP1AirBuilder, Word, WordAirBuilder}; -use crate::cpu::columns::{CpuCols, OpcodeSelectorCols}; -use crate::operations::BabyBearWordRangeChecker; -use crate::{cpu::CpuChip, runtime::Opcode}; +use sp1_stark::{ + air::{BaseAirBuilder, SP1AirBuilder}, + Word, +}; + +use crate::{ + air::WordAirBuilder, + cpu::{ + columns::{CpuCols, OpcodeSelectorCols}, + CpuChip, + }, + operations::BabyBearWordRangeChecker, +}; + +use sp1_core_executor::Opcode; impl CpuChip { /// Computes whether the opcode is a branch instruction. @@ -23,8 +33,8 @@ impl CpuChip { /// Verifies all the branching related columns. /// /// It does this in few parts: - /// 1. It verifies that the next pc is correct based on the branching column. That column - /// is a boolean that indicates whether the branch condition is true. + /// 1. It verifies that the next pc is correct based on the branching column. That column is a + /// boolean that indicates whether the branch condition is true. /// 2. It verifies the correct value of branching based on the helper bool columns (a_eq_b, /// a_gt_b, a_lt_b). /// 3. It verifier the correct values of the helper bool columns based on op_a and op_b. @@ -41,9 +51,7 @@ impl CpuChip { // Evaluate program counter constraints. { // When we are branching, assert local.pc <==> branch_cols.pc as Word. - builder - .when(local.branching) - .assert_eq(branch_cols.pc.reduce::(), local.pc); + builder.when(local.branching).assert_eq(branch_cols.pc.reduce::(), local.pc); // When we are branching, assert that next.pc <==> branch_columns.next_pc as Word. builder @@ -52,7 +60,8 @@ impl CpuChip { .when(local.branching) .assert_eq(branch_cols.next_pc.reduce::(), next.pc); - // When the current row is real and local.branching, assert that local.next_pc <==> branch_columns.next_pc as Word. + // When the current row is real and local.branching, assert that local.next_pc <==> + // branch_columns.next_pc as Word. builder .when(local.is_real) .when(local.branching) @@ -94,30 +103,26 @@ impl CpuChip { // When local.not_branching is true, assert that local.is_real is true. builder.when(local.not_branching).assert_one(local.is_real); - // When the last row is real and local.not_branching, assert that local.pc + 4 <==> local.next_pc. + // When the last row is real and local.not_branching, assert that local.pc + 4 <==> + // local.next_pc. builder .when(local.is_real) .when(local.not_branching) .assert_eq(local.pc + AB::Expr::from_canonical_u8(4), local.next_pc); - // Assert that either we are branching or not branching when the instruction is a branch. + // Assert that either we are branching or not branching when the instruction is a + // branch. builder .when(is_branch_instruction.clone()) .assert_one(local.branching + local.not_branching); - builder - .when(is_branch_instruction.clone()) - .assert_bool(local.branching); - builder - .when(is_branch_instruction.clone()) - .assert_bool(local.not_branching); + builder.when(is_branch_instruction.clone()).assert_bool(local.branching); + builder.when(is_branch_instruction.clone()).assert_bool(local.not_branching); } // Evaluate branching value constraints. { // When the opcode is BEQ and we are branching, assert that a_eq_b is true. - builder - .when(local.selectors.is_beq * local.branching) - .assert_one(branch_cols.a_eq_b); + builder.when(local.selectors.is_beq * local.branching).assert_one(branch_cols.a_eq_b); // When the opcode is BEQ and we are not branching, assert that either a_gt_b or a_lt_b // is true. @@ -169,9 +174,7 @@ impl CpuChip { .assert_word_eq(local.op_a_val(), local.op_b_val()); // To prevent this ALU send to be arbitrarily large when is_branch_instruction is false. - builder - .when_not(is_branch_instruction.clone()) - .assert_zero(local.branching); + builder.when_not(is_branch_instruction.clone()).assert_zero(local.branching); // Calculate a_lt_b <==> a < b (using appropriate signedness). let use_signed_comparison = local.selectors.is_blt + local.selectors.is_bge; diff --git a/core/src/cpu/air/ecall.rs b/crates/core/machine/src/cpu/air/ecall.rs similarity index 89% rename from core/src/cpu/air/ecall.rs rename to crates/core/machine/src/cpu/air/ecall.rs index ff7cda017f..8a88453a7a 100644 --- a/core/src/cpu/air/ecall.rs +++ b/crates/core/machine/src/cpu/air/ecall.rs @@ -1,13 +1,20 @@ use p3_air::AirBuilder; use p3_field::AbstractField; - -use crate::air::{BaseAirBuilder, PublicValues, WordAirBuilder}; -use crate::cpu::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}; -use crate::cpu::columns::{CpuCols, OpcodeSelectorCols}; -use crate::memory::MemoryCols; -use crate::operations::{BabyBearWordRangeChecker, IsZeroOperation}; -use crate::runtime::SyscallCode; -use crate::stark::{CpuChip, SP1AirBuilder}; +use sp1_core_executor::syscalls::SyscallCode; +use sp1_stark::{ + air::{BaseAirBuilder, PublicValues, SP1AirBuilder, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}, + Word, +}; + +use crate::{ + air::WordAirBuilder, + cpu::{ + columns::{CpuCols, OpcodeSelectorCols}, + CpuChip, + }, + memory::MemoryCols, + operations::{BabyBearWordRangeChecker, IsZeroOperation}, +}; impl CpuChip { /// Whether the instruction is an ECALL instruction. @@ -38,10 +45,8 @@ impl CpuChip { // Handle cases: // - is_ecall_instruction = 1 => ecall_mul_send_to_table == send_to_table // - is_ecall_instruction = 0 => ecall_mul_send_to_table == 0 - builder.assert_eq( - local.ecall_mul_send_to_table, - send_to_table * is_ecall_instruction.clone(), - ); + builder + .assert_eq(local.ecall_mul_send_to_table, send_to_table * is_ecall_instruction.clone()); builder.send_syscall( local.shard, @@ -154,17 +159,14 @@ impl CpuChip { local.selectors.is_ecall * (is_commit.clone() + is_commit_deferred_proofs.clone()), ) - .assert_eq( - local.op_b_access.prev_value()[i + 1], - AB::Expr::from_canonical_u32(0), - ); + .assert_eq(local.op_b_access.prev_value()[i + 1], AB::Expr::from_canonical_u32(0)); } // Retrieve the expected public values digest word to check against the one passed into the - // commit ecall. Note that for the interaction builder, it will not have any digest words, since - // it's used during AIR compilation time to parse for all send/receives. Since that interaction - // builder will ignore the other constraints of the air, it is safe to not include the - // verification check of the expected public values digest word. + // commit ecall. Note that for the interaction builder, it will not have any digest words, + // since it's used during AIR compilation time to parse for all send/receives. Since + // that interaction builder will ignore the other constraints of the air, it is safe + // to not include the verification check of the expected public values digest word. let expected_pv_digest_word = builder.index_word_array(&commit_digest, &ecall_columns.index_bitmap); @@ -185,10 +187,7 @@ impl CpuChip { builder .when(local.selectors.is_ecall * is_commit_deferred_proofs) - .assert_eq( - expected_deferred_proofs_digest_element, - digest_word.reduce::(), - ); + .assert_eq(expected_deferred_proofs_digest_element, digest_word.reduce::()); } /// Constraint related to the halt and unimpl instruction. @@ -215,10 +214,9 @@ impl CpuChip { .when(is_halt.clone()) .assert_word_eq(local.op_b_val(), ecall_columns.operand_to_check); - builder.when(is_halt.clone()).assert_eq( - local.op_b_access.value().reduce::(), - public_values.exit_code.clone(), - ); + builder + .when(is_halt.clone()) + .assert_eq(local.op_b_access.value().reduce::(), public_values.exit_code.clone()); } /// Returns a boolean expression indicating whether the instruction is a HALT instruction. @@ -249,7 +247,8 @@ impl CpuChip { is_halt * is_ecall_instruction } - /// Returns two boolean expression indicating whether the instruction is a COMMIT or COMMIT_DEFERRED_PROOFS instruction. + /// Returns two boolean expression indicating whether the instruction is a COMMIT or + /// COMMIT_DEFERRED_PROOFS instruction. pub(crate) fn get_is_commit_related_syscall( &self, builder: &mut AB, diff --git a/core/src/cpu/air/memory.rs b/crates/core/machine/src/cpu/air/memory.rs similarity index 79% rename from core/src/cpu/air/memory.rs rename to crates/core/machine/src/cpu/air/memory.rs index 707a50ff95..4ab7e1036e 100644 --- a/core/src/cpu/air/memory.rs +++ b/crates/core/machine/src/cpu/air/memory.rs @@ -1,12 +1,17 @@ use p3_air::AirBuilder; use p3_field::AbstractField; - -use crate::air::{BaseAirBuilder, SP1AirBuilder, Word, WordAirBuilder}; -use crate::cpu::columns::{CpuCols, MemoryColumns, OpcodeSelectorCols}; -use crate::cpu::CpuChip; -use crate::memory::MemoryCols; -use crate::operations::BabyBearWordRangeChecker; -use crate::runtime::{MemoryAccessPosition, Opcode}; +use sp1_stark::{air::SP1AirBuilder, Word}; + +use crate::{ + air::{SP1CoreAirBuilder, WordAirBuilder}, + cpu::{ + columns::{CpuCols, MemoryColumns, OpcodeSelectorCols}, + CpuChip, + }, + memory::MemoryCols, + operations::BabyBearWordRangeChecker, +}; +use sp1_core_executor::{events::MemoryAccessPosition, Opcode}; impl CpuChip { /// Computes whether the opcode is a memory instruction. @@ -49,8 +54,9 @@ impl CpuChip { /// This method will do the following: /// 1. Calculate that the unaligned address is correctly computed to be op_b.value + op_c.value. /// 2. Calculate that the address offset is address % 4. - /// 3. Assert the validity of the aligned address given the address offset and the unaligned address. - pub(crate) fn eval_memory_address_and_access( + /// 3. Assert the validity of the aligned address given the address offset and the unaligned + /// address. + pub(crate) fn eval_memory_address_and_access( &self, builder: &mut AB, local: &CpuCols, @@ -91,12 +97,10 @@ impl CpuChip { self.eval_offset_value_flags(builder, memory_columns, local); // Assert that reduce(addr_word) == addr_aligned + addr_offset. - builder - .when(is_memory_instruction.clone()) - .assert_eq::( - memory_columns.addr_aligned + memory_columns.addr_offset, - memory_columns.addr_word.reduce::(), - ); + builder.when(is_memory_instruction.clone()).assert_eq::( + memory_columns.addr_aligned + memory_columns.addr_offset, + memory_columns.addr_word.reduce::(), + ); // Verify that the least significant byte of addr_word - addr_offset is divisible by 4. let offset = [ @@ -110,18 +114,12 @@ impl CpuChip { acc + AB::Expr::from_canonical_usize(index + 1) * value }); let mut recomposed_byte = AB::Expr::zero(); - memory_columns - .aa_least_sig_byte_decomp - .iter() - .enumerate() - .for_each(|(i, value)| { - builder - .when(is_memory_instruction.clone()) - .assert_bool(*value); - - recomposed_byte = - recomposed_byte.clone() + AB::Expr::from_canonical_usize(1 << (i + 2)) * *value; - }); + memory_columns.aa_least_sig_byte_decomp.iter().enumerate().for_each(|(i, value)| { + builder.when(is_memory_instruction.clone()).assert_bool(*value); + + recomposed_byte = + recomposed_byte.clone() + AB::Expr::from_canonical_usize(1 << (i + 2)) * *value; + }); builder .when(is_memory_instruction.clone()) @@ -139,12 +137,10 @@ impl CpuChip { ); // On memory load instructions, make sure that the memory value is not changed. - builder - .when(self.is_load_instruction::(&local.selectors)) - .assert_word_eq( - *memory_columns.memory_access.value(), - *memory_columns.memory_access.prev_value(), - ); + builder.when(self.is_load_instruction::(&local.selectors)).assert_word_eq( + *memory_columns.memory_access.value(), + *memory_columns.memory_access.prev_value(), + ); } /// Evaluates constraints related to loading from memory. @@ -156,9 +152,6 @@ impl CpuChip { // Get the memory specific columns. let memory_columns = local.opcode_specific_columns.memory(); - // Compute whether this is a load instruction. - let is_load = self.is_load_instruction::(&local.selectors); - // Verify the unsigned_mem_value column. self.eval_unsigned_mem_value(builder, memory_columns, local); @@ -166,16 +159,16 @@ impl CpuChip { // of the most significant byte to get it's sign. self.eval_most_sig_byte_bit_decomp(builder, memory_columns, local, &local.unsigned_mem_val); - // Assert that if `is_lb` and `is_lh` are both true, then the most significant byte - // matches the value of `local.mem_value_is_neg`. + // Assert that correct value of `mem_value_is_neg_not_x0`. builder.assert_eq( - local.mem_value_is_neg, + local.mem_value_is_neg_not_x0, (local.selectors.is_lb + local.selectors.is_lh) - * memory_columns.most_sig_byte_decomp[7], + * memory_columns.most_sig_byte_decomp[7] + * (AB::Expr::one() - local.instruction.op_a_0), ); - // When the memory value is negative, use the SUB opcode to compute the signed value of - // the memory value and verify that the op_a value is correct. + // When the memory value is negative and not writing to x0, use the SUB opcode to compute + // the signed value of the memory value and verify that the op_a value is correct. let signed_value = Word([ AB::Expr::zero(), AB::Expr::one() * local.selectors.is_lb, @@ -190,14 +183,24 @@ impl CpuChip { local.shard, local.channel, local.unsigned_mem_val_nonce, - local.mem_value_is_neg, + local.mem_value_is_neg_not_x0, + ); + + // Assert that correct value of `mem_value_is_pos_not_x0`. + let mem_value_is_pos = (local.selectors.is_lb + local.selectors.is_lh) + * (AB::Expr::one() - memory_columns.most_sig_byte_decomp[7]) + + local.selectors.is_lbu + + local.selectors.is_lhu + + local.selectors.is_lw; + builder.assert_eq( + local.mem_value_is_pos_not_x0, + mem_value_is_pos * (AB::Expr::one() - local.instruction.op_a_0), ); - // When the memory value is not negaitve, assert that op_a value is equal to the unsigned - // memory value. + // When the memory value is not positive and not writing to x0, assert that op_a value is + // equal to the unsigned memory value. builder - .when(is_load) - .when_not(local.mem_value_is_neg) + .when(local.mem_value_is_pos_not_x0) .assert_word_eq(local.unsigned_mem_val, local.op_a_val()); } @@ -212,7 +215,8 @@ impl CpuChip { // Get the memory offset flags. self.eval_offset_value_flags(builder, memory_columns, local); // Compute the offset_is_zero flag. The other offset flags are already contrained by the - // method `eval_memory_address_and_access`, which is called in `eval_memory_address_and_access`. + // method `eval_memory_address_and_access`, which is called in + // `eval_memory_address_and_access`. let offset_is_zero = AB::Expr::one() - memory_columns.offset_is_one - memory_columns.offset_is_two @@ -243,9 +247,7 @@ impl CpuChip { .assert_zero(memory_columns.offset_is_one + memory_columns.offset_is_three); // When the instruction is SW, ensure that the offset is 0. - builder - .when(local.selectors.is_sw) - .assert_one(offset_is_zero.clone()); + builder.when(local.selectors.is_sw).assert_one(offset_is_zero.clone()); // Compute the expected stored value for a SH instruction. let a_is_lower_half = offset_is_zero; @@ -267,7 +269,8 @@ impl CpuChip { .assert_word_eq(mem_val.map(|x| x.into()), a_val.map(|x| x.into())); } - /// This function is used to evaluate the unsigned memory value for the load memory instructions. + /// This function is used to evaluate the unsigned memory value for the load memory + /// instructions. pub(crate) fn eval_unsigned_mem_value( &self, builder: &mut AB, @@ -277,7 +280,8 @@ impl CpuChip { let mem_val = *memory_columns.memory_access.value(); // Compute the offset_is_zero flag. The other offset flags are already contrained by the - // method `eval_memory_address_and_access`, which is called in `eval_memory_address_and_access`. + // method `eval_memory_address_and_access`, which is called in + // `eval_memory_address_and_access`. let offset_is_zero = AB::Expr::one() - memory_columns.offset_is_one - memory_columns.offset_is_two @@ -301,9 +305,7 @@ impl CpuChip { .assert_zero(memory_columns.offset_is_one + memory_columns.offset_is_three); // When the instruction is LW, ensure that the offset is zero. - builder - .when(local.selectors.is_lw) - .assert_one(offset_is_zero.clone()); + builder.when(local.selectors.is_lw).assert_one(offset_is_zero.clone()); let use_lower_half = offset_is_zero; let use_upper_half = memory_columns.offset_is_two; @@ -318,9 +320,7 @@ impl CpuChip { .assert_word_eq(half_value, local.unsigned_mem_val.map(|x| x.into())); // When the instruction is LW, just use the word. - builder - .when(local.selectors.is_lw) - .assert_word_eq(mem_val, local.unsigned_mem_val); + builder.when(local.selectors.is_lw).assert_word_eq(mem_val, local.unsigned_mem_val); } /// Evaluates the decomposition of the most significant byte of the memory value. @@ -334,18 +334,12 @@ impl CpuChip { let is_mem = self.is_memory_instruction::(&local.selectors); let mut recomposed_byte = AB::Expr::zero(); for i in 0..8 { - builder - .when(is_mem.clone()) - .assert_bool(memory_columns.most_sig_byte_decomp[i]); + builder.when(is_mem.clone()).assert_bool(memory_columns.most_sig_byte_decomp[i]); recomposed_byte += memory_columns.most_sig_byte_decomp[i] * AB::Expr::from_canonical_u8(1 << i); } - builder - .when(local.selectors.is_lb) - .assert_eq(recomposed_byte.clone(), unsigned_mem_val[0]); - builder - .when(local.selectors.is_lh) - .assert_eq(recomposed_byte, unsigned_mem_val[1]); + builder.when(local.selectors.is_lb).assert_eq(recomposed_byte.clone(), unsigned_mem_val[0]); + builder.when(local.selectors.is_lh).assert_eq(recomposed_byte, unsigned_mem_val[1]); } /// Evaluates the offset value flags. @@ -377,12 +371,8 @@ impl CpuChip { ); // Assert that the correct value flag is set - filtered_builder - .when(offset_is_zero) - .assert_zero(memory_columns.addr_offset); - filtered_builder - .when(memory_columns.offset_is_one) - .assert_one(memory_columns.addr_offset); + filtered_builder.when(offset_is_zero).assert_zero(memory_columns.addr_offset); + filtered_builder.when(memory_columns.offset_is_one).assert_one(memory_columns.addr_offset); filtered_builder .when(memory_columns.offset_is_two) .assert_eq(memory_columns.addr_offset, AB::Expr::two()); diff --git a/core/src/cpu/air/mod.rs b/crates/core/machine/src/cpu/air/mod.rs similarity index 81% rename from core/src/cpu/air/mod.rs rename to crates/core/machine/src/cpu/air/mod.rs index 05d6a3fdc3..880e76e36c 100644 --- a/core/src/cpu/air/mod.rs +++ b/crates/core/machine/src/cpu/air/mod.rs @@ -4,33 +4,30 @@ pub mod memory; pub mod register; use core::borrow::Borrow; -use p3_air::Air; -use p3_air::AirBuilder; -use p3_air::AirBuilderWithPublicValues; -use p3_air::BaseAir; +use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; use p3_field::AbstractField; use p3_matrix::Matrix; - -use crate::air::BaseAirBuilder; -use crate::air::PublicValues; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::air::POSEIDON_NUM_WORDS; -use crate::air::PV_DIGEST_NUM_WORDS; -use crate::air::SP1_PROOF_NUM_PV_ELTS; -use crate::bytes::ByteOpcode; -use crate::cpu::columns::OpcodeSelectorCols; -use crate::cpu::columns::{CpuCols, NUM_CPU_COLS}; -use crate::cpu::CpuChip; -use crate::operations::BabyBearWordRangeChecker; -use crate::runtime::Opcode; - -use super::columns::eval_channel_selectors; -use super::columns::OPCODE_SELECTORS_COL_MAP; +use sp1_core_executor::ByteOpcode; +use sp1_stark::{ + air::{BaseAirBuilder, PublicValues, SP1AirBuilder, SP1_PROOF_NUM_PV_ELTS}, + Word, +}; + +use crate::{ + air::{MemoryAirBuilder, SP1CoreAirBuilder}, + cpu::{ + columns::{CpuCols, OpcodeSelectorCols, NUM_CPU_COLS}, + CpuChip, + }, + operations::BabyBearWordRangeChecker, +}; +use sp1_core_executor::Opcode; + +use super::columns::{eval_channel_selectors, OPCODE_SELECTORS_COL_MAP}; impl Air for CpuChip where - AB: SP1AirBuilder + AirBuilderWithPublicValues, + AB: SP1CoreAirBuilder + AirBuilderWithPublicValues, AB::Var: Sized, { #[inline(never)] @@ -124,25 +121,15 @@ where self.eval_is_real(builder, local, next); // Check that when `is_real=0` that all flags that send interactions are zero. - local - .selectors - .into_iter() - .enumerate() - .for_each(|(i, selector)| { - if i == OPCODE_SELECTORS_COL_MAP.imm_b { - builder - .when(AB::Expr::one() - local.is_real) - .assert_one(local.selectors.imm_b); - } else if i == OPCODE_SELECTORS_COL_MAP.imm_c { - builder - .when(AB::Expr::one() - local.is_real) - .assert_one(local.selectors.imm_c); - } else { - builder - .when(AB::Expr::one() - local.is_real) - .assert_zero(selector); - } - }); + local.selectors.into_iter().enumerate().for_each(|(i, selector)| { + if i == OPCODE_SELECTORS_COL_MAP.imm_b { + builder.when(AB::Expr::one() - local.is_real).assert_one(local.selectors.imm_b); + } else if i == OPCODE_SELECTORS_COL_MAP.imm_c { + builder.when(AB::Expr::one() - local.is_real).assert_one(local.selectors.imm_c); + } else { + builder.when(AB::Expr::one() - local.is_real).assert_zero(selector); + } + }); } } @@ -174,15 +161,10 @@ impl CpuChip { builder .when(is_jump_instruction.clone()) .when_not(local.instruction.op_a_0) - .assert_eq( - local.op_a_val().reduce::(), - local.pc + AB::F::from_canonical_u8(4), - ); + .assert_eq(local.op_a_val().reduce::(), local.pc + AB::F::from_canonical_u8(4)); // Verify that the word form of local.pc is correct for JAL instructions. - builder - .when(local.selectors.is_jal) - .assert_eq(jump_columns.pc.reduce::(), local.pc); + builder.when(local.selectors.is_jal).assert_eq(jump_columns.pc.reduce::(), local.pc); // Verify that the word form of next.pc is correct for both jump instructions. builder @@ -191,7 +173,8 @@ impl CpuChip { .when(is_jump_instruction.clone()) .assert_eq(jump_columns.next_pc.reduce::(), next.pc); - // When the last row is real and it's a jump instruction, assert that local.next_pc <==> jump_column.next_pc + // When the last row is real and it's a jump instruction, assert that local.next_pc <==> + // jump_column.next_pc builder .when(local.is_real) .when(is_jump_instruction.clone()) @@ -248,9 +231,7 @@ impl CpuChip { let auipc_columns = local.opcode_specific_columns.auipc(); // Verify that the word form of local.pc is correct. - builder - .when(local.selectors.is_auipc) - .assert_eq(auipc_columns.pc.reduce::(), local.pc); + builder.when(local.selectors.is_auipc).assert_eq(auipc_columns.pc.reduce::(), local.pc); // Range check the pc. BabyBearWordRangeChecker::::range_check( @@ -278,7 +259,8 @@ impl CpuChip { /// This method ensures that all of the shard values are the same and that the clk starts at 0 /// and is transitioned apporpriately. It will also check that shard values are within 16 bits /// and clk values are within 24 bits. Those range checks are needed for the memory access - /// timestamp check, which assumes those values are within 2^24. See [`MemoryAirBuilder::verify_mem_access_ts`]. + /// timestamp check, which assumes those values are within 2^24. See + /// [`MemoryAirBuilder::verify_mem_access_ts`]. pub(crate) fn eval_shard_clk( &self, builder: &mut AB, @@ -286,10 +268,7 @@ impl CpuChip { next: &CpuCols, ) { // Verify that all shard values are the same. - builder - .when_transition() - .when(next.is_real) - .assert_eq(local.shard, next.shard); + builder.when_transition().when(next.is_real).assert_eq(local.shard, next.shard); // Verify that the shard value is within 16 bits. builder.send_byte( @@ -314,10 +293,7 @@ impl CpuChip { let expected_next_clk = local.clk + AB::Expr::from_canonical_u32(4) + num_extra_cycles.clone(); - builder - .when_transition() - .when(next.is_real) - .assert_eq(expected_next_clk.clone(), next.clk); + builder.when_transition().when(next.is_real).assert_eq(expected_next_clk.clone(), next.clk); // Range check that the clk is within 24 bits using it's limb values. builder.eval_range_check_24bits( @@ -332,8 +308,9 @@ impl CpuChip { /// Constraints related to the pc for non jump, branch, and halt instructions. /// - /// The function will verify that the pc increments by 4 for all instructions except branch, jump - /// and halt instructions. Also, it ensures that the pc is carried down to the last row for non-real rows. + /// The function will verify that the pc increments by 4 for all instructions except branch, + /// jump and halt instructions. Also, it ensures that the pc is carried down to the last row + /// for non-real rows. pub(crate) fn eval_pc( &self, builder: &mut AB, @@ -353,15 +330,17 @@ impl CpuChip { + is_halt), ); - // Verify that the pc increments by 4 for all instructions except branch, jump and halt instructions. - // The other case is handled by eval_jump, eval_branch and eval_ecall (for halt). + // Verify that the pc increments by 4 for all instructions except branch, jump and halt + // instructions. The other case is handled by eval_jump, eval_branch and eval_ecall + // (for halt). builder .when_transition() .when(next.is_real) .when(local.is_sequential_instr) .assert_eq(local.pc + AB::Expr::from_canonical_u8(4), next.pc); - // When the last row is real and it's a sequential instruction, assert that local.next_pc <==> local.pc + 4 + // When the last row is real and it's a sequential instruction, assert that local.next_pc + // <==> local.pc + 4 builder .when(local.is_real) .when(local.is_sequential_instr) @@ -377,14 +356,10 @@ impl CpuChip { public_values: &PublicValues, AB::Expr>, ) { // Verify the public value's shard. - builder - .when(local.is_real) - .assert_eq(public_values.execution_shard.clone(), local.shard); + builder.when(local.is_real).assert_eq(public_values.execution_shard.clone(), local.shard); // Verify the public value's start pc. - builder - .when_first_row() - .assert_eq(public_values.start_pc.clone(), local.pc); + builder.when_first_row().assert_eq(public_values.start_pc.clone(), local.pc); // Verify the public value's next pc. We need to handle two cases: // 1. The last real row is a transition row. @@ -417,10 +392,7 @@ impl CpuChip { // change value. builder.assert_bool(local.is_real); builder.when_first_row().assert_one(local.is_real); - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when_not(local.is_real).assert_zero(next.is_real); } } diff --git a/core/src/cpu/air/register.rs b/crates/core/machine/src/cpu/air/register.rs similarity index 88% rename from core/src/cpu/air/register.rs rename to crates/core/machine/src/cpu/air/register.rs index 23b6551d16..8ffa86248c 100644 --- a/core/src/cpu/air/register.rs +++ b/crates/core/machine/src/cpu/air/register.rs @@ -1,10 +1,12 @@ use p3_field::AbstractField; +use sp1_stark::air::SP1AirBuilder; -use crate::air::WordAirBuilder; -use crate::cpu::columns::CpuCols; -use crate::memory::MemoryCols; -use crate::runtime::MemoryAccessPosition; -use crate::stark::{CpuChip, SP1AirBuilder}; +use crate::{ + air::{MemoryAirBuilder, WordAirBuilder}, + cpu::{columns::CpuCols, CpuChip}, + memory::MemoryCols, +}; +use sp1_core_executor::events::MemoryAccessPosition; impl CpuChip { /// Computes whether the opcode is a branch instruction. @@ -42,9 +44,7 @@ impl CpuChip { ); // If we are writing to register 0, then the new value should be zero. - builder - .when(local.instruction.op_a_0) - .assert_word_zero(*local.op_a_access.value()); + builder.when(local.instruction.op_a_0).assert_word_zero(*local.op_a_access.value()); // Write the `a` or the result to the first register described in the instruction unless // we are performing a branch or a store. diff --git a/core/src/cpu/columns/auipc.rs b/crates/core/machine/src/cpu/columns/auipc.rs similarity index 83% rename from core/src/cpu/columns/auipc.rs rename to crates/core/machine/src/cpu/columns/auipc.rs index fa6871c211..5505f213b3 100644 --- a/core/src/cpu/columns/auipc.rs +++ b/crates/core/machine/src/cpu/columns/auipc.rs @@ -1,7 +1,8 @@ use sp1_derive::AlignedBorrow; +use sp1_stark::Word; use std::mem::size_of; -use crate::{air::Word, operations::BabyBearWordRangeChecker}; +use crate::operations::BabyBearWordRangeChecker; pub const NUM_AUIPC_COLS: usize = size_of::>(); diff --git a/core/src/cpu/columns/branch.rs b/crates/core/machine/src/cpu/columns/branch.rs similarity index 92% rename from core/src/cpu/columns/branch.rs rename to crates/core/machine/src/cpu/columns/branch.rs index c6298ef0f7..6f12f5a675 100644 --- a/core/src/cpu/columns/branch.rs +++ b/crates/core/machine/src/cpu/columns/branch.rs @@ -1,7 +1,8 @@ use sp1_derive::AlignedBorrow; +use sp1_stark::Word; use std::mem::size_of; -use crate::{air::Word, operations::BabyBearWordRangeChecker}; +use crate::operations::BabyBearWordRangeChecker; pub const NUM_BRANCH_COLS: usize = size_of::>(); diff --git a/core/src/cpu/columns/channel.rs b/crates/core/machine/src/cpu/columns/channel.rs similarity index 77% rename from core/src/cpu/columns/channel.rs rename to crates/core/machine/src/cpu/columns/channel.rs index bc55a9acad..1f1d6ec535 100644 --- a/core/src/cpu/columns/channel.rs +++ b/crates/core/machine/src/cpu/columns/channel.rs @@ -1,9 +1,9 @@ use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::SP1AirBuilder; -use crate::{bytes::NUM_BYTE_LOOKUP_CHANNELS, stark::SP1AirBuilder}; +use crate::bytes::NUM_BYTE_LOOKUP_CHANNELS; #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] #[repr(C)] @@ -43,24 +43,17 @@ pub fn eval_channel_selectors( // Assert that the reconstructed channel is the same as the channel. builder.assert_eq(reconstruct_channel, channel.clone()); // For disjointness, assert the sum of the selectors is 1. - builder - .when(local_is_real.clone()) - .assert_eq(sum, AB::Expr::one()); + builder.when(local_is_real.clone()).assert_eq(sum, AB::Expr::one()); // Constrain the first row by asserting that the first selector on the first line is true. - builder - .when_first_row() - .assert_one(local.channel_selectors[0]); + builder.when_first_row().assert_one(local.channel_selectors[0]); // Constrain the transition by asserting that the selectors satisfy the recursion relation: // selectors_next[(i + 1) % NUM_BYTE_LOOKUP_CHANNELS] = selectors[i] for i in 0..NUM_BYTE_LOOKUP_CHANNELS as usize { - builder - .when_transition() - .when(next_is_real.clone()) - .assert_eq( - local.channel_selectors[i], - next.channel_selectors[(i + 1) % NUM_BYTE_LOOKUP_CHANNELS as usize], - ); + builder.when_transition().when(next_is_real.clone()).assert_eq( + local.channel_selectors[i], + next.channel_selectors[(i + 1) % NUM_BYTE_LOOKUP_CHANNELS as usize], + ); } } diff --git a/core/src/cpu/columns/ecall.rs b/crates/core/machine/src/cpu/columns/ecall.rs similarity index 84% rename from core/src/cpu/columns/ecall.rs rename to crates/core/machine/src/cpu/columns/ecall.rs index 649708f19f..ea737c169e 100644 --- a/core/src/cpu/columns/ecall.rs +++ b/crates/core/machine/src/cpu/columns/ecall.rs @@ -1,10 +1,8 @@ use sp1_derive::AlignedBorrow; +use sp1_stark::{air::PV_DIGEST_NUM_WORDS, Word}; use std::mem::size_of; -use crate::{ - air::{Word, PV_DIGEST_NUM_WORDS}, - operations::{BabyBearWordRangeChecker, IsZeroOperation}, -}; +use crate::operations::{BabyBearWordRangeChecker, IsZeroOperation}; pub const NUM_ECALL_COLS: usize = size_of::>(); @@ -26,8 +24,8 @@ pub struct EcallCols { /// Whether the current ecall is a COMMIT_DEFERRED_PROOFS. pub is_commit_deferred_proofs: IsZeroOperation, - /// Field to store the word index passed into the COMMIT ecall. index_bitmap[word index] should - /// be set to 1 and everything else set to 0. + /// Field to store the word index passed into the COMMIT ecall. index_bitmap[word index] + /// should be set to 1 and everything else set to 0. pub index_bitmap: [T; PV_DIGEST_NUM_WORDS], /// The nonce of the syscall operation. diff --git a/core/src/cpu/columns/instruction.rs b/crates/core/machine/src/cpu/columns/instruction.rs similarity index 90% rename from core/src/cpu/columns/instruction.rs rename to crates/core/machine/src/cpu/columns/instruction.rs index 5e5aab4b7a..a16de4fb08 100644 --- a/core/src/cpu/columns/instruction.rs +++ b/crates/core/machine/src/cpu/columns/instruction.rs @@ -1,10 +1,8 @@ use p3_field::PrimeField; +use sp1_core_executor::{Instruction, Register}; use sp1_derive::AlignedBorrow; -use std::mem::size_of; -use std::{iter::once, vec::IntoIter}; - -use crate::runtime::Register; -use crate::{air::Word, runtime::Instruction}; +use sp1_stark::Word; +use std::{iter::once, mem::size_of, vec::IntoIter}; pub const NUM_INSTRUCTION_COLS: usize = size_of::>(); diff --git a/core/src/cpu/columns/jump.rs b/crates/core/machine/src/cpu/columns/jump.rs similarity index 89% rename from core/src/cpu/columns/jump.rs rename to crates/core/machine/src/cpu/columns/jump.rs index 0e1b5701f5..579f2b5160 100644 --- a/core/src/cpu/columns/jump.rs +++ b/crates/core/machine/src/cpu/columns/jump.rs @@ -1,7 +1,8 @@ use sp1_derive::AlignedBorrow; +use sp1_stark::Word; use std::mem::size_of; -use crate::{air::Word, operations::BabyBearWordRangeChecker}; +use crate::operations::BabyBearWordRangeChecker; pub const NUM_JUMP_COLS: usize = size_of::>(); diff --git a/core/src/cpu/columns/memory.rs b/crates/core/machine/src/cpu/columns/memory.rs similarity index 86% rename from core/src/cpu/columns/memory.rs rename to crates/core/machine/src/cpu/columns/memory.rs index baab9e1fc0..3eb52337ab 100644 --- a/core/src/cpu/columns/memory.rs +++ b/crates/core/machine/src/cpu/columns/memory.rs @@ -1,7 +1,8 @@ use sp1_derive::AlignedBorrow; +use sp1_stark::Word; use std::mem::size_of; -use crate::{air::Word, memory::MemoryReadWriteCols, operations::BabyBearWordRangeChecker}; +use crate::{memory::MemoryReadWriteCols, operations::BabyBearWordRangeChecker}; pub const NUM_MEMORY_COLUMNS: usize = size_of::>(); @@ -29,8 +30,8 @@ pub struct MemoryColumns { pub offset_is_two: T, pub offset_is_three: T, - // LE bit decomposition for the most significant byte of memory value. This is used to determine - // the sign for that value (used for LB and LH). + // LE bit decomposition for the most significant byte of memory value. This is used to + // determine the sign for that value (used for LB and LH). pub most_sig_byte_decomp: [T; 8], pub addr_word_nonce: T, diff --git a/core/src/cpu/columns/mod.rs b/crates/core/machine/src/cpu/columns/mod.rs similarity index 82% rename from core/src/cpu/columns/mod.rs rename to crates/core/machine/src/cpu/columns/mod.rs index e0ceec7aa2..3f382677ee 100644 --- a/core/src/cpu/columns/mod.rs +++ b/crates/core/machine/src/cpu/columns/mod.rs @@ -20,12 +20,10 @@ pub use opcode_specific::*; use p3_util::indices_arr; use sp1_derive::AlignedBorrow; +use sp1_stark::Word; use std::mem::{size_of, transmute}; -use crate::{ - air::Word, - memory::{MemoryCols, MemoryReadCols, MemoryReadWriteCols}, -}; +use crate::memory::{MemoryCols, MemoryReadCols, MemoryReadWriteCols}; pub const NUM_CPU_COLS: usize = size_of::>(); @@ -90,10 +88,21 @@ pub struct CpuCols { /// > (is_bge | is_bgeu) & !(a_eq_b | a_gt_b) pub not_branching: T, - /// The memory value is negative column is equal to: + /// Flag for load mem instructions where the value is negative and not writing to x0. + /// More formally, it is /// - /// > (is_lbu | is_lhu) & (most_sig_byte_decomp[7] == 1) - pub mem_value_is_neg: T, + /// > (is_lb | is_lh) & (most_sig_byte_decomp[7] == 1) & (not writing to x0) + pub mem_value_is_neg_not_x0: T, + + /// Flag for load mem instructions where the value is positive and not writing to x0. + /// More formally, it is + /// + /// ( + /// ((is_lb | is_lh) & (most_sig_byte_decomp[7] == 0)) | + /// is_lbu | is_lhu | is_lw + /// ) & + /// (not writing to x0) + pub mem_value_is_pos_not_x0: T, /// The unsigned memory value is the value after the offset logic is applied. Used for the load /// memory opcodes (i.e. LB, LH, LW, LBU, and LHU). @@ -107,8 +116,8 @@ pub struct CpuCols { /// The result of selectors.is_ecall * (is_halt || is_commit_deferred_proofs) pub ecall_range_check_operand: T, - /// This is true for all instructions that are not jumps, branches, and halt. Those instructions - /// may move the program counter to a non sequential instruction. + /// This is true for all instructions that are not jumps, branches, and halt. Those + /// instructions may move the program counter to a non sequential instruction. pub is_sequential_instr: T, } diff --git a/core/src/cpu/columns/opcode.rs b/crates/core/machine/src/cpu/columns/opcode.rs similarity index 96% rename from core/src/cpu/columns/opcode.rs rename to crates/core/machine/src/cpu/columns/opcode.rs index 80fd63ad3d..9b4344d036 100644 --- a/core/src/cpu/columns/opcode.rs +++ b/crates/core/machine/src/cpu/columns/opcode.rs @@ -1,13 +1,13 @@ use p3_field::PrimeField; +use sp1_core_executor::{Instruction, Opcode}; use sp1_derive::AlignedBorrow; -use std::mem::{size_of, transmute}; -use std::vec::IntoIter; - -use crate::{ - runtime::{Instruction, Opcode}, - utils::indices_arr, +use std::{ + mem::{size_of, transmute}, + vec::IntoIter, }; +use crate::utils::indices_arr; + pub const NUM_OPCODE_SELECTOR_COLS: usize = size_of::>(); pub const OPCODE_SELECTORS_COL_MAP: OpcodeSelectorCols = make_selectors_col_map(); diff --git a/core/src/cpu/columns/opcode_specific.rs b/crates/core/machine/src/cpu/columns/opcode_specific.rs similarity index 93% rename from core/src/cpu/columns/opcode_specific.rs rename to crates/core/machine/src/cpu/columns/opcode_specific.rs index 4a6d9207f7..8406434ef7 100644 --- a/core/src/cpu/columns/opcode_specific.rs +++ b/crates/core/machine/src/cpu/columns/opcode_specific.rs @@ -1,6 +1,8 @@ use crate::cpu::columns::{AuipcCols, BranchCols, JumpCols, MemoryColumns}; -use std::fmt::{Debug, Formatter}; -use std::mem::{size_of, transmute}; +use std::{ + fmt::{Debug, Formatter}, + mem::{size_of, transmute}, +}; use static_assertions::const_assert; @@ -24,9 +26,7 @@ impl Default for OpcodeSpecificCols { // We must use the largest field to avoid uninitialized padding bytes. const_assert!(size_of::>() == size_of::>()); - OpcodeSpecificCols { - memory: MemoryColumns::default(), - } + OpcodeSpecificCols { memory: MemoryColumns::default() } } } diff --git a/core/src/cpu/mod.rs b/crates/core/machine/src/cpu/mod.rs similarity index 87% rename from core/src/cpu/mod.rs rename to crates/core/machine/src/cpu/mod.rs index c9c513ab64..d0191a9ea7 100644 --- a/core/src/cpu/mod.rs +++ b/crates/core/machine/src/cpu/mod.rs @@ -1,10 +1,7 @@ pub mod air; pub mod columns; -pub mod event; pub mod trace; -pub use event::*; - /// The maximum log degree of the CPU chip to avoid lookup multiplicity overflow. pub const MAX_CPU_LOG_DEGREE: usize = 22; diff --git a/core/src/cpu/trace.rs b/crates/core/machine/src/cpu/trace.rs similarity index 78% rename from core/src/cpu/trace.rs rename to crates/core/machine/src/cpu/trace.rs index 48428b4f74..5c9d413cb6 100644 --- a/core/src/cpu/trace.rs +++ b/crates/core/machine/src/cpu/trace.rs @@ -1,30 +1,31 @@ use hashbrown::HashMap; use itertools::Itertools; -use std::array; -use std::borrow::BorrowMut; +use sp1_core_executor::{ + events::{ + create_alu_lookups, AluEvent, ByteLookupEvent, ByteRecord, CpuEvent, MemoryRecordEnum, + }, + syscalls::SyscallCode, + ByteOpcode, + ByteOpcode::U16Range, + ExecutionRecord, Opcode, Program, + Register::X0, +}; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::MachineAir, Word}; +use std::{array, borrow::BorrowMut}; use p3_field::{PrimeField, PrimeField32}; use p3_matrix::dense::RowMajorMatrix; -use p3_maybe_rayon::prelude::IntoParallelRefMutIterator; -use p3_maybe_rayon::prelude::ParallelBridge; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSlice; +use p3_maybe_rayon::prelude::{ + IntoParallelRefMutIterator, ParallelBridge, ParallelIterator, ParallelSlice, +}; use tracing::instrument; -use super::columns::{CPU_COL_MAP, NUM_CPU_COLS}; -use super::{CpuChip, CpuEvent}; -use crate::air::MachineAir; -use crate::air::Word; -use crate::alu::create_alu_lookups; -use crate::alu::{self, AluEvent}; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::cpu::columns::CpuCols; -use crate::cpu::trace::ByteOpcode::{U16Range, U8Range}; -use crate::disassembler::WORD_SIZE; -use crate::memory::MemoryCols; -use crate::runtime::{ExecutionRecord, Opcode, Program}; -use crate::runtime::{MemoryRecordEnum, SyscallCode}; +use super::{ + columns::{CPU_COL_MAP, NUM_CPU_COLS}, + CpuChip, +}; +use crate::{cpu::columns::CpuCols, memory::MemoryCols}; impl MachineAir for CpuChip { type Record = ExecutionRecord; @@ -43,25 +44,21 @@ impl MachineAir for CpuChip { let mut values = vec![F::zero(); input.cpu_events.len() * NUM_CPU_COLS]; let chunk_size = std::cmp::max(input.cpu_events.len() / num_cpus::get(), 1); - values - .chunks_mut(chunk_size * NUM_CPU_COLS) - .enumerate() - .par_bridge() - .for_each(|(i, rows)| { - rows.chunks_mut(NUM_CPU_COLS) - .enumerate() - .for_each(|(j, row)| { - let idx = i * chunk_size + j; - let cols: &mut CpuCols = row.borrow_mut(); - let mut byte_lookup_events = Vec::new(); - self.event_to_row( - &input.cpu_events[idx], - &input.nonce_lookup, - cols, - &mut byte_lookup_events, - ); - }); - }); + values.chunks_mut(chunk_size * NUM_CPU_COLS).enumerate().par_bridge().for_each( + |(i, rows)| { + rows.chunks_mut(NUM_CPU_COLS).enumerate().for_each(|(j, row)| { + let idx = i * chunk_size + j; + let cols: &mut CpuCols = row.borrow_mut(); + let mut byte_lookup_events = Vec::new(); + self.event_to_row( + &input.cpu_events[idx], + &input.nonce_lookup, + cols, + &mut byte_lookup_events, + ); + }); + }, + ); // Convert the trace to a row major matrix. let mut trace = RowMajorMatrix::new(values, NUM_CPU_COLS); @@ -116,7 +113,7 @@ impl CpuChip { nonce_lookup: &HashMap, cols: &mut CpuCols, blu_events: &mut impl ByteRecord, - ) -> HashMap> { + ) -> HashMap> { let mut new_alu_events = HashMap::new(); // Populate shard and clk columns. @@ -124,10 +121,7 @@ impl CpuChip { // Populate the nonce. cols.nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.alu_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.alu_lookup_id).copied().unwrap_or_default(), ); // Populate basic fields. @@ -182,9 +176,7 @@ impl CpuChip { assert_eq!(event.memory_record.is_some(), event.memory.is_some()); let memory_columns = cols.opcode_specific_columns.memory_mut(); if let Some(record) = event.memory_record { - memory_columns - .memory_access - .populate(event.channel, record, blu_events) + memory_columns.memory_access.populate(event.channel, record, blu_events) } // Populate memory, branch, jump, and auipc specific fields. @@ -245,7 +237,7 @@ impl CpuChip { blu_events.add_byte_lookup_event(ByteLookupEvent::new( event.shard, event.channel, - U8Range, + ByteOpcode::U8Range, 0, 0, 0, @@ -258,7 +250,7 @@ impl CpuChip { &self, cols: &mut CpuCols, event: &CpuEvent, - new_alu_events: &mut HashMap>, + new_alu_events: &mut HashMap>, blu_events: &mut impl ByteRecord, nonce_lookup: &HashMap, ) { @@ -307,10 +299,7 @@ impl CpuChip { .and_modify(|op_new_events| op_new_events.push(add_event)) .or_insert(vec![add_event]); memory_columns.addr_word_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.memory_add_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.memory_add_lookup_id).copied().unwrap_or_default(), ); // Populate memory offsets. @@ -363,7 +352,8 @@ impl CpuChip { F::from_canonical_u8(most_sig_mem_value_byte >> i & 0x01); } if memory_columns.most_sig_byte_decomp[7] == F::one() { - cols.mem_value_is_neg = F::one(); + cols.mem_value_is_neg_not_x0 = + F::from_bool(event.instruction.op_a != (X0 as u32)); let sub_event = AluEvent { lookup_id: event.memory_sub_lookup_id, channel: event.channel, @@ -376,10 +366,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; cols.unsigned_mem_val_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.memory_sub_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.memory_sub_lookup_id).copied().unwrap_or_default(), ); new_alu_events @@ -388,6 +375,14 @@ impl CpuChip { .or_insert(vec![sub_event]); } } + + // Set the `mem_value_is_pos_not_x0` composite flag. + cols.mem_value_is_pos_not_x0 = F::from_bool( + ((matches!(event.instruction.opcode, Opcode::LB | Opcode::LH) + && (memory_columns.most_sig_byte_decomp[7] == F::zero())) + || matches!(event.instruction.opcode, Opcode::LBU | Opcode::LHU | Opcode::LW)) + && event.instruction.op_a != (X0 as u32), + ); } // Add event to byte lookup for byte range checking each byte in the memory addr @@ -410,7 +405,7 @@ impl CpuChip { &self, cols: &mut CpuCols, event: &CpuEvent, - alu_events: &mut HashMap>, + alu_events: &mut HashMap>, nonce_lookup: &HashMap, ) { if event.instruction.is_branch_instruction() { @@ -432,11 +427,7 @@ impl CpuChip { event.a > event.b }; - let alu_op_code = if use_signed_comparison { - Opcode::SLT - } else { - Opcode::SLTU - }; + let alu_op_code = if use_signed_comparison { Opcode::SLT } else { Opcode::SLTU }; // Add the ALU events for the comparisons let lt_comp_event = AluEvent { @@ -451,10 +442,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; branch_columns.a_lt_b_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.branch_lt_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.branch_lt_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -474,10 +462,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; branch_columns.a_gt_b_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.branch_gt_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.branch_gt_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -518,10 +503,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; branch_columns.next_pc_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.branch_add_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.branch_add_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -539,7 +521,7 @@ impl CpuChip { &self, cols: &mut CpuCols, event: &CpuEvent, - alu_events: &mut HashMap>, + alu_events: &mut HashMap>, nonce_lookup: &HashMap, ) { if event.instruction.is_jump_instruction() { @@ -566,10 +548,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; jump_columns.jal_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.jump_jal_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.jump_jal_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -595,10 +574,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; jump_columns.jalr_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.jump_jalr_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.jump_jalr_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -616,7 +592,7 @@ impl CpuChip { &self, cols: &mut CpuCols, event: &CpuEvent, - alu_events: &mut HashMap>, + alu_events: &mut HashMap>, nonce_lookup: &HashMap, ) { if matches!(event.instruction.opcode, Opcode::AUIPC) { @@ -637,10 +613,7 @@ impl CpuChip { sub_lookups: create_alu_lookups(), }; auipc_columns.auipc_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.auipc_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.auipc_lookup_id).copied().unwrap_or_default(), ); alu_events @@ -661,7 +634,8 @@ impl CpuChip { if cols.selectors.is_ecall == F::one() { // The send_to_table column is the 1st entry of the op_a_access column prev_value field. - // Look at `ecall_eval` in cpu/air/mod.rs for the corresponding constraint and explanation. + // Look at `ecall_eval` in cpu/air/mod.rs for the corresponding constraint and + // explanation. let ecall_cols = cols.opcode_specific_columns.ecall_mut(); cols.ecall_mul_send_to_table = cols.selectors.is_ecall * cols.op_a_access.prev_value[1]; @@ -671,12 +645,9 @@ impl CpuChip { // let num_cycles = cols.op_a_access.prev_value[2]; // Populate `is_enter_unconstrained`. - ecall_cols - .is_enter_unconstrained - .populate_from_field_element( - syscall_id - - F::from_canonical_u32(SyscallCode::ENTER_UNCONSTRAINED.syscall_id()), - ); + ecall_cols.is_enter_unconstrained.populate_from_field_element( + syscall_id - F::from_canonical_u32(SyscallCode::ENTER_UNCONSTRAINED.syscall_id()), + ); // Populate `is_hint_len`. ecall_cols.is_hint_len.populate_from_field_element( @@ -694,14 +665,13 @@ impl CpuChip { ); // Populate `is_commit_deferred_proofs`. - ecall_cols - .is_commit_deferred_proofs - .populate_from_field_element( - syscall_id - - F::from_canonical_u32(SyscallCode::COMMIT_DEFERRED_PROOFS.syscall_id()), - ); + ecall_cols.is_commit_deferred_proofs.populate_from_field_element( + syscall_id + - F::from_canonical_u32(SyscallCode::COMMIT_DEFERRED_PROOFS.syscall_id()), + ); - // If the syscall is `COMMIT` or `COMMIT_DEFERRED_PROOFS`, set the index bitmap and digest word. + // If the syscall is `COMMIT` or `COMMIT_DEFERRED_PROOFS`, set the index bitmap and + // digest word. if syscall_id == F::from_canonical_u32(SyscallCode::COMMIT.syscall_id()) || syscall_id == F::from_canonical_u32(SyscallCode::COMMIT_DEFERRED_PROOFS.syscall_id()) @@ -712,10 +682,7 @@ impl CpuChip { // Write the syscall nonce. ecall_cols.syscall_nonce = F::from_canonical_u32( - nonce_lookup - .get(&event.syscall_lookup_id) - .copied() - .unwrap_or_default(), + nonce_lookup.get(&event.syscall_lookup_id).copied().unwrap_or_default(), ); is_halt = syscall_id == F::from_canonical_u32(SyscallCode::HALT.syscall_id()); @@ -741,11 +708,7 @@ impl CpuChip { fn pad_to_power_of_two(values: &mut Vec) { let n_real_rows = values.len() / NUM_CPU_COLS; - let padded_nb_rows = if n_real_rows < 16 { - 16 - } else { - n_real_rows.next_power_of_two() - }; + let padded_nb_rows = if n_real_rows < 16 { 16 } else { n_real_rows.next_power_of_two() }; values.resize(padded_nb_rows * NUM_CPU_COLS, F::zero()); // Interpret values as a slice of arrays of length `NUM_CPU_COLS` @@ -762,79 +725,3 @@ impl CpuChip { }); } } - -#[cfg(test)] -mod tests { - use p3_baby_bear::BabyBear; - - use std::time::Instant; - - use super::*; - - use crate::runtime::tests::ssz_withdrawals_program; - use crate::runtime::{tests::simple_program, Runtime}; - use crate::stark::CpuProver; - use crate::utils::{run_test, setup_logger, SP1CoreOpts}; - - // #[test] - // fn generate_trace() { - // let mut shard = ExecutionRecord::default(); - // shard.cpu_events = vec![CpuEvent { - // shard: 1, - // channel: 0, - // clk: 6, - // pc: 1, - // next_pc: 5, - // instruction: Instruction { - // opcode: Opcode::ADD, - // op_a: 0, - // op_b: 1, - // op_c: 2, - // imm_b: false, - // imm_c: false, - // }, - // a: 1, - // a_record: None, - // b: 2, - // b_record: None, - // c: 3, - // c_record: None, - // memory: None, - // memory_record: None, - // exit_code: 0, - // }]; - // let chip = CpuChip::default(); - // let trace: RowMajorMatrix = - // chip.generate_trace(&shard, &mut ExecutionRecord::default()); - // println!("{:?}", trace.values); - // } - - #[test] - fn generate_trace_simple_program() { - let program = ssz_withdrawals_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); - runtime.run().unwrap(); - println!("runtime: {:?}", runtime.state.global_clk); - let chip = CpuChip::default(); - - let start = Instant::now(); - >::generate_dependencies( - &chip, - &runtime.record, - &mut ExecutionRecord::default(), - ); - println!("generate dependencies: {:?}", start.elapsed()); - - let start = Instant::now(); - let _: RowMajorMatrix = - chip.generate_trace(&runtime.record, &mut ExecutionRecord::default()); - println!("generate trace: {:?}", start.elapsed()); - } - - #[test] - fn prove_trace() { - setup_logger(); - let program = simple_program(); - run_test::>(program).unwrap(); - } -} diff --git a/core/src/io.rs b/crates/core/machine/src/io.rs similarity index 89% rename from core/src/io.rs rename to crates/core/machine/src/io.rs index 98d8ad5154..ee6c652f73 100644 --- a/core/src/io.rs +++ b/crates/core/machine/src/io.rs @@ -1,10 +1,8 @@ -use crate::{ - stark::{ShardProof, StarkVerifyingKey}, - utils::{BabyBearPoseidon2, Buffer}, -}; +use crate::utils::Buffer; use k256::sha2::{Digest, Sha256}; use num_bigint::BigUint; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, ShardProof, StarkVerifyingKey}; /// Standard input for the prover. #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -13,10 +11,7 @@ pub struct SP1Stdin { /// a vec of bytes at a time. pub buffer: Vec>, pub ptr: usize, - pub proofs: Vec<( - ShardProof, - StarkVerifyingKey, - )>, + pub proofs: Vec<(ShardProof, StarkVerifyingKey)>, } /// Public values for the prover. @@ -28,20 +23,12 @@ pub struct SP1PublicValues { impl SP1Stdin { /// Create a new `SP1Stdin`. pub const fn new() -> Self { - Self { - buffer: Vec::new(), - ptr: 0, - proofs: Vec::new(), - } + Self { buffer: Vec::new(), ptr: 0, proofs: Vec::new() } } /// Create a `SP1Stdin` from a slice of bytes. pub fn from(data: &[u8]) -> Self { - Self { - buffer: vec![data.to_vec()], - ptr: 0, - proofs: Vec::new(), - } + Self { buffer: vec![data.to_vec()], ptr: 0, proofs: Vec::new() } } /// Read a value from the buffer. @@ -86,9 +73,7 @@ impl SP1Stdin { impl SP1PublicValues { /// Create a new `SP1PublicValues`. pub const fn new() -> Self { - Self { - buffer: Buffer::new(), - } + Self { buffer: Buffer::new() } } pub fn raw(&self) -> String { @@ -97,9 +82,7 @@ impl SP1PublicValues { /// Create a `SP1PublicValues` from a slice of bytes. pub fn from(data: &[u8]) -> Self { - Self { - buffer: Buffer::from(data), - } + Self { buffer: Buffer::from(data) } } pub fn as_slice(&self) -> &[u8] { @@ -159,8 +142,7 @@ impl AsRef<[u8]> for SP1PublicValues { pub mod proof_serde { use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; - - use crate::stark::{MachineProof, StarkGenericConfig}; + use sp1_stark::{MachineProof, StarkGenericConfig}; pub fn serialize( proof: &MachineProof, diff --git a/core/src/lib.rs b/crates/core/machine/src/lib.rs similarity index 79% rename from core/src/lib.rs rename to crates/core/machine/src/lib.rs index 7de36a6f03..de273e65c3 100644 --- a/core/src/lib.rs +++ b/crates/core/machine/src/lib.rs @@ -17,24 +17,17 @@ pub mod air; pub mod alu; pub mod bytes; pub mod cpu; -pub mod disassembler; pub mod io; -pub mod lookup; pub mod memory; pub mod operations; pub mod program; -pub mod runtime; -pub mod stark; +pub mod riscv; pub mod syscall; pub mod utils; -#[allow(unused_imports)] -use runtime::{Program, Runtime}; -use stark::StarkGenericConfig; - /// The global version for all components of SP1. /// /// This string should be updated whenever any step in verifying an SP1 proof changes, including /// core, recursion, and plonk-bn254. This string is used to download SP1 artifacts and the gnark /// docker image. -pub const SP1_CIRCUIT_VERSION: &str = "v1.1.0"; +pub const SP1_CIRCUIT_VERSION: &str = "v1.2.0-rc1"; diff --git a/core/src/memory/columns.rs b/crates/core/machine/src/memory/columns.rs similarity index 88% rename from core/src/memory/columns.rs rename to crates/core/machine/src/memory/columns.rs index 86e4dbf57d..5e589c6d0b 100644 --- a/core/src/memory/columns.rs +++ b/crates/core/machine/src/memory/columns.rs @@ -1,6 +1,5 @@ use sp1_derive::AlignedBorrow; - -use crate::air::Word; +use sp1_stark::Word; /// Memory read access. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -38,14 +37,16 @@ pub struct MemoryAccessCols { /// This will be true if the current shard == prev_access's shard, else false. pub compare_clk: T, - /// The following columns are decomposed limbs for the difference between the current access's timestamp - /// and the previous access's timestamp. Note the actual value of the timestamp is either the - /// accesses' shard or clk depending on the value of compare_clk. + /// The following columns are decomposed limbs for the difference between the current access's + /// timestamp and the previous access's timestamp. Note the actual value of the timestamp + /// is either the accesses' shard or clk depending on the value of compare_clk. - /// This column is the least significant 16 bit limb of current access timestamp - prev access timestamp. + /// This column is the least significant 16 bit limb of current access timestamp - prev access + /// timestamp. pub diff_16bit_limb: T, - /// This column is the most signficant 8 bit limb of current access timestamp - prev access timestamp. + /// This column is the most signficant 8 bit limb of current access timestamp - prev access + /// timestamp. pub diff_8bit_limb: T, } @@ -145,8 +146,5 @@ impl MemoryCols for MemoryReadWriteCols { /// A utility method to convert a slice of memory access columns into a vector of values. /// This is useful for comparing the values of a memory access to limbs. pub fn value_as_limbs>(memory: &[M]) -> Vec { - memory - .iter() - .flat_map(|m| m.value().clone().into_iter()) - .collect() + memory.iter().flat_map(|m| m.value().clone().into_iter()).collect() } diff --git a/core/src/memory/global.rs b/crates/core/machine/src/memory/global.rs similarity index 82% rename from core/src/memory/global.rs rename to crates/core/machine/src/memory/global.rs index bdd5b7e82f..b956f8155e 100644 --- a/core/src/memory/global.rs +++ b/crates/core/machine/src/memory/global.rs @@ -1,20 +1,26 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use std::array; -use p3_air::BaseAir; -use p3_air::{Air, AirBuilder}; +use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField32}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{events::MemoryInitializeFinalizeEvent, ExecutionRecord, Program}; use sp1_derive::AlignedBorrow; - -use super::MemoryInitializeFinalizeEvent; -use crate::air::{AirInteraction, BaseAirBuilder, PublicValues, SP1AirBuilder, Word}; -use crate::air::{MachineAir, SP1_PROOF_NUM_PV_ELTS}; -use crate::operations::{AssertLtColsBits, BabyBearBitDecomposition, IsZeroOperation}; -use crate::runtime::{ExecutionRecord, Program}; -use crate::utils::pad_to_power_of_two; +use sp1_stark::{ + air::{ + AirInteraction, BaseAirBuilder, MachineAir, PublicValues, SP1AirBuilder, + SP1_PROOF_NUM_PV_ELTS, + }, + InteractionKind, Word, +}; + +use crate::{ + operations::{AssertLtColsBits, BabyBearBitDecomposition, IsZeroOperation}, + utils::pad_to_power_of_two, +}; /// The type of memory chip that is being initialized. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -75,13 +81,8 @@ impl MachineAir for MemoryChip { memory_events.sort_by_key(|event| event.addr); let rows: Vec<[F; NUM_MEMORY_INIT_COLS]> = (0..memory_events.len()) // OPT: change this to par_iter .map(|i| { - let MemoryInitializeFinalizeEvent { - addr, - value, - shard, - timestamp, - used, - } = memory_events[i]; + let MemoryInitializeFinalizeEvent { addr, value, shard, timestamp, used } = + memory_events[i]; let mut row = [F::zero(); NUM_MEMORY_INIT_COLS]; let cols: &mut MemoryInitCols = row.as_mut_slice().borrow_mut(); @@ -217,19 +218,15 @@ where builder.receive(AirInteraction::new( values, local.is_real.into(), - crate::lookup::InteractionKind::Memory, + InteractionKind::Memory, )); } else { - let mut values = vec![ - local.shard.into(), - local.timestamp.into(), - local.addr.into(), - ]; + let mut values = vec![local.shard.into(), local.timestamp.into(), local.addr.into()]; values.extend(value); builder.send(AirInteraction::new( values, local.is_real.into(), - crate::lookup::InteractionKind::Memory, + InteractionKind::Memory, )); } @@ -254,21 +251,11 @@ where // - In the last real row, we need to assert that addr = last_finalize_addr. // Assert that addr < addr' when the next row is real. - builder - .when_transition() - .assert_eq(next.is_next_comp, next.is_real); - next.lt_cols.eval( - builder, - &local.addr_bits.bits, - &next.addr_bits.bits, - next.is_next_comp, - ); + builder.when_transition().assert_eq(next.is_next_comp, next.is_real); + next.lt_cols.eval(builder, &local.addr_bits.bits, &next.addr_bits.bits, next.is_next_comp); // Assert that the real rows are all padded to the top. - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when_not(local.is_real).assert_zero(next.is_real); // Make assertions for the initial comparison. @@ -305,47 +292,30 @@ where // Constrain the is_first_comp column. builder.assert_bool(local.is_first_comp); - builder.when_first_row().assert_eq( - local.is_first_comp, - AB::Expr::one() - local.is_prev_addr_zero.result, - ); + builder + .when_first_row() + .assert_eq(local.is_first_comp, AB::Expr::one() - local.is_prev_addr_zero.result); // Ensure at least one real row. builder.when_first_row().assert_one(local.is_real); // Constrain the inequality assertion in the first row. - local.lt_cols.eval( - builder, - prev_addr_bits, - &local_addr_bits, - local.is_first_comp, - ); + local.lt_cols.eval(builder, prev_addr_bits, &local_addr_bits, local.is_first_comp); // Insure that there are no duplicate initializations by assuring there is exactly one // initialization event of the zero address. This is done by assuring that when the previous // address is zero, then the first row address is also zero, and that the second row is also // real, and the less than comparison is being made. - builder - .when_first_row() - .when(local.is_prev_addr_zero.result) - .assert_zero(local.addr); - builder - .when_first_row() - .when(local.is_prev_addr_zero.result) - .assert_one(next.is_real); + builder.when_first_row().when(local.is_prev_addr_zero.result).assert_zero(local.addr); + builder.when_first_row().when(local.is_prev_addr_zero.result).assert_one(next.is_real); // Ensure that in the address zero case the comparison is being made so that there is an // address bigger than zero being committed to. - builder - .when_first_row() - .when(local.is_prev_addr_zero.result) - .assert_one(next.is_next_comp); + builder.when_first_row().when(local.is_prev_addr_zero.result).assert_one(next.is_next_comp); // Make assertions for specific types of memory chips. if self.kind == MemoryChipType::Initialize { - builder - .when(local.is_real) - .assert_eq(local.timestamp, AB::F::one()); + builder.when(local.is_real).assert_eq(local.timestamp, AB::F::one()); } // Constraints related to register %x0. @@ -359,10 +329,7 @@ where // once, this can be constrained by the public values setting `previous_init_addr_bits` or // `previous_finalize_addr_bits` to zero. for i in 0..32 { - builder - .when_first_row() - .when_not(local.is_first_comp) - .assert_zero(local.value[i]); + builder.when_first_row().when_not(local.is_first_comp).assert_zero(local.value[i]); } // Make assertions for the final value. We need to connect the final valid address to the @@ -376,17 +343,13 @@ where // - The flag `is_real` is set to one and the next `is_real` is set to zero. // Constrain the `is_last_addr` flag. - builder.when_transition().assert_eq( - local.is_last_addr, - local.is_real * (AB::Expr::one() - next.is_real), - ); + builder + .when_transition() + .assert_eq(local.is_last_addr, local.is_real * (AB::Expr::one() - next.is_real)); // Constrain the last address bits to be equal to the corresponding `last_addr_bits` value. for (local_bit, pub_bit) in local.addr_bits.bits.iter().zip(last_addr_bits.iter()) { - builder - .when_last_row() - .when(local.is_real) - .assert_eq(*local_bit, pub_bit.clone()); + builder.when_last_row().when(local.is_real).assert_eq(*local_bit, pub_bit.clone()); builder .when_transition() .when(local.is_last_addr) @@ -399,18 +362,21 @@ where mod tests { use super::*; - use crate::lookup::{debug_interactions_with_all_chips, InteractionKind}; - use crate::runtime::tests::simple_program; - use crate::runtime::Runtime; - use crate::stark::RiscvAir; - use crate::syscall::precompiles::sha256::extend_tests::sha_extend_program; - use crate::utils::{setup_logger, BabyBearPoseidon2, SP1CoreOpts}; + use crate::{ + riscv::RiscvAir, syscall::precompiles::sha256::extend_tests::sha_extend_program, + utils::setup_logger, + }; use p3_baby_bear::BabyBear; + use sp1_core_executor::{programs::tests::simple_program, Executor}; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, debug_interactions_with_all_chips, SP1CoreOpts, + StarkMachine, + }; #[test] fn test_memory_generate_trace() { let program = simple_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); let shard = runtime.record.clone(); @@ -435,9 +401,9 @@ mod tests { setup_logger(); let program = sha_extend_program(); let program_clone = program.clone(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); - let machine: crate::stark::StarkMachine> = + let machine: StarkMachine> = RiscvAir::machine(BabyBearPoseidon2::new()); let (pkey, _) = machine.setup(&program_clone); let opts = SP1CoreOpts::default(); @@ -458,7 +424,7 @@ mod tests { setup_logger(); let program = sha_extend_program(); let program_clone = program.clone(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); let machine = RiscvAir::machine(BabyBearPoseidon2::new()); let (pkey, _) = machine.setup(&program_clone); diff --git a/crates/core/machine/src/memory/mod.rs b/crates/core/machine/src/memory/mod.rs new file mode 100644 index 0000000000..13f9050f31 --- /dev/null +++ b/crates/core/machine/src/memory/mod.rs @@ -0,0 +1,8 @@ +mod columns; +mod global; +mod program; +mod trace; + +pub use columns::*; +pub use global::*; +pub use program::*; diff --git a/core/src/memory/program.rs b/crates/core/machine/src/memory/program.rs similarity index 86% rename from core/src/memory/program.rs rename to crates/core/machine/src/memory/program.rs index 3adf5aec1f..8f396fa7a5 100644 --- a/core/src/memory/program.rs +++ b/crates/core/machine/src/memory/program.rs @@ -1,18 +1,19 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir, PairBuilder}; -use p3_field::AbstractField; -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, PrimeField}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ExecutionRecord, Program}; use sp1_derive::AlignedBorrow; +use sp1_stark::{ + air::{AirInteraction, MachineAir, PublicValues, SP1AirBuilder, SP1_PROOF_NUM_PV_ELTS}, + InteractionKind, Word, +}; -use crate::air::{AirInteraction, PublicValues, SP1AirBuilder, SP1_PROOF_NUM_PV_ELTS}; -use crate::air::{MachineAir, Word}; -use crate::operations::IsZeroOperation; -use crate::runtime::{ExecutionRecord, Program}; -use crate::utils::pad_to_power_of_two; +use crate::{operations::IsZeroOperation, utils::pad_to_power_of_two}; pub const NUM_MEMORY_PROGRAM_PREPROCESSED_COLS: usize = size_of::>(); @@ -102,18 +103,9 @@ impl MachineAir for MemoryProgramChip { input: &ExecutionRecord, _output: &mut ExecutionRecord, ) -> RowMajorMatrix { - let program_memory_addrs = input - .program - .memory_image - .keys() - .copied() - .collect::>(); + let program_memory_addrs = input.program.memory_image.keys().copied().collect::>(); - let mult = if input.public_values.shard == 1 { - F::one() - } else { - F::zero() - }; + let mult = if input.public_values.shard == 1 { F::one() } else { F::zero() }; // Generate the trace rows for each event. let rows = program_memory_addrs @@ -187,16 +179,14 @@ where .assert_eq(mult_local.multiplicity, prep_local.is_real.into()); // If it's not the first shard, then the multiplicity must be zero. - builder - .when_not(mult_local.is_first_shard.result) - .assert_zero(mult_local.multiplicity); + builder.when_not(mult_local.is_first_shard.result).assert_zero(mult_local.multiplicity); let mut values = vec![AB::Expr::zero(), AB::Expr::zero(), prep_local.addr.into()]; values.extend(prep_local.value.map(Into::into)); builder.receive(AirInteraction::new( values, mult_local.multiplicity.into(), - crate::lookup::InteractionKind::Memory, + InteractionKind::Memory, )); } } diff --git a/core/src/memory/trace.rs b/crates/core/machine/src/memory/trace.rs similarity index 69% rename from core/src/memory/trace.rs rename to crates/core/machine/src/memory/trace.rs index d3f60e9a3a..7dd5b12586 100644 --- a/core/src/memory/trace.rs +++ b/crates/core/machine/src/memory/trace.rs @@ -1,8 +1,9 @@ use p3_field::PrimeField32; +use sp1_core_executor::events::{ + ByteRecord, MemoryReadRecord, MemoryRecord, MemoryRecordEnum, MemoryWriteRecord, +}; use super::{MemoryAccessCols, MemoryReadCols, MemoryReadWriteCols, MemoryWriteCols}; -use crate::bytes::event::ByteRecord; -use crate::runtime::{MemoryReadRecord, MemoryRecord, MemoryRecordEnum, MemoryWriteRecord}; impl MemoryWriteCols { pub fn populate( @@ -11,19 +12,15 @@ impl MemoryWriteCols { record: MemoryWriteRecord, output: &mut impl ByteRecord, ) { - let current_record = MemoryRecord { - value: record.value, - shard: record.shard, - timestamp: record.timestamp, - }; + let current_record = + MemoryRecord { value: record.value, shard: record.shard, timestamp: record.timestamp }; let prev_record = MemoryRecord { value: record.prev_value, shard: record.prev_shard, timestamp: record.prev_timestamp, }; self.prev_value = prev_record.value.into(); - self.access - .populate_access(channel, current_record, prev_record, output); + self.access.populate_access(channel, current_record, prev_record, output); } } @@ -34,18 +31,14 @@ impl MemoryReadCols { record: MemoryReadRecord, output: &mut impl ByteRecord, ) { - let current_record = MemoryRecord { - value: record.value, - shard: record.shard, - timestamp: record.timestamp, - }; + let current_record = + MemoryRecord { value: record.value, shard: record.shard, timestamp: record.timestamp }; let prev_record = MemoryRecord { value: record.value, shard: record.prev_shard, timestamp: record.prev_timestamp, }; - self.access - .populate_access(channel, current_record, prev_record, output); + self.access.populate_access(channel, current_record, prev_record, output); } } @@ -70,19 +63,15 @@ impl MemoryReadWriteCols { record: MemoryWriteRecord, output: &mut impl ByteRecord, ) { - let current_record = MemoryRecord { - value: record.value, - shard: record.shard, - timestamp: record.timestamp, - }; + let current_record = + MemoryRecord { value: record.value, shard: record.shard, timestamp: record.timestamp }; let prev_record = MemoryRecord { value: record.prev_value, shard: record.prev_shard, timestamp: record.prev_timestamp, }; self.prev_value = prev_record.value.into(); - self.access - .populate_access(channel, current_record, prev_record, output); + self.access.populate_access(channel, current_record, prev_record, output); } pub fn populate_read( @@ -91,19 +80,15 @@ impl MemoryReadWriteCols { record: MemoryReadRecord, output: &mut impl ByteRecord, ) { - let current_record = MemoryRecord { - value: record.value, - shard: record.shard, - timestamp: record.timestamp, - }; + let current_record = + MemoryRecord { value: record.value, shard: record.shard, timestamp: record.timestamp }; let prev_record = MemoryRecord { value: record.value, shard: record.prev_shard, timestamp: record.prev_timestamp, }; self.prev_value = prev_record.value.into(); - self.access - .populate_access(channel, current_record, prev_record, output); + self.access.populate_access(channel, current_record, prev_record, output); } } @@ -120,19 +105,14 @@ impl MemoryAccessCols { self.prev_shard = F::from_canonical_u32(prev_record.shard); self.prev_clk = F::from_canonical_u32(prev_record.timestamp); - // Fill columns used for verifying current memory access time value is greater than previous's. + // Fill columns used for verifying current memory access time value is greater than + // previous's. let use_clk_comparison = prev_record.shard == current_record.shard; self.compare_clk = F::from_bool(use_clk_comparison); - let prev_time_value = if use_clk_comparison { - prev_record.timestamp - } else { - prev_record.shard - }; - let current_time_value = if use_clk_comparison { - current_record.timestamp - } else { - current_record.shard - }; + let prev_time_value = + if use_clk_comparison { prev_record.timestamp } else { prev_record.shard }; + let current_time_value = + if use_clk_comparison { current_record.timestamp } else { current_record.shard }; let diff_minus_one = current_time_value - prev_time_value - 1; let diff_16bit_limb = (diff_minus_one & 0xffff) as u16; diff --git a/core/src/operations/add.rs b/crates/core/machine/src/operations/add.rs similarity index 93% rename from core/src/operations/add.rs rename to crates/core/machine/src/operations/add.rs index 3b9a2b90fb..5e1172b487 100644 --- a/core/src/operations/add.rs +++ b/crates/core/machine/src/operations/add.rs @@ -1,12 +1,12 @@ -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; +use sp1_core_executor::events::ByteRecord; +use sp1_stark::{air::SP1AirBuilder, Word}; use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; +use crate::air::WordAirBuilder; + /// A set of columns needed to compute the add of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] #[repr(C)] @@ -47,9 +47,7 @@ impl AddOperation { } let base = 256u32; - let overflow = a[0] - .wrapping_add(b[0]) - .wrapping_sub(expected.to_le_bytes()[0]) as u32; + let overflow = a[0].wrapping_add(b[0]).wrapping_sub(expected.to_le_bytes()[0]) as u32; debug_assert_eq!(overflow.wrapping_mul(overflow.wrapping_sub(base)), 0); // Range check diff --git a/core/src/operations/add4.rs b/crates/core/machine/src/operations/add4.rs similarity index 93% rename from core/src/operations/add4.rs rename to crates/core/machine/src/operations/add4.rs index 1bcb2f1cae..5fe5ec0fd1 100644 --- a/core/src/operations/add4.rs +++ b/crates/core/machine/src/operations/add4.rs @@ -1,12 +1,12 @@ use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::air::WORD_SIZE; -use crate::bytes::event::ByteRecord; +use sp1_core_executor::events::ByteRecord; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; + +use crate::air::WordAirBuilder; /// A set of columns needed to compute the add of four words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -24,7 +24,8 @@ pub struct Add4Operation { /// Indicates if the carry for the `i`th digit is 2. pub is_carry_2: Word, - /// Indicates if the carry for the `i`th digit is 3. The carry when adding 4 words is at most 3. + /// Indicates if the carry for the `i`th digit is 3. The carry when adding 4 words is at most + /// 3. pub is_carry_3: Word, /// The carry for the `i`th digit. @@ -43,10 +44,7 @@ impl Add4Operation { c_u32: u32, d_u32: u32, ) -> u32 { - let expected = a_u32 - .wrapping_add(b_u32) - .wrapping_add(c_u32) - .wrapping_add(d_u32); + let expected = a_u32.wrapping_add(b_u32).wrapping_add(c_u32).wrapping_add(d_u32); self.value = Word::from(expected); let a = a_u32.to_le_bytes(); let b = b_u32.to_le_bytes(); diff --git a/core/src/operations/add5.rs b/crates/core/machine/src/operations/add5.rs similarity index 94% rename from core/src/operations/add5.rs rename to crates/core/machine/src/operations/add5.rs index 60b86dd6cc..959d06dd10 100644 --- a/core/src/operations/add5.rs +++ b/crates/core/machine/src/operations/add5.rs @@ -1,12 +1,12 @@ use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::air::WORD_SIZE; -use crate::bytes::event::ByteRecord; +use sp1_core_executor::events::ByteRecord; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; + +use crate::air::WordAirBuilder; /// A set of columns needed to compute the sum of five words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -47,11 +47,8 @@ impl Add5Operation { d_u32: u32, e_u32: u32, ) -> u32 { - let expected = a_u32 - .wrapping_add(b_u32) - .wrapping_add(c_u32) - .wrapping_add(d_u32) - .wrapping_add(e_u32); + let expected = + a_u32.wrapping_add(b_u32).wrapping_add(c_u32).wrapping_add(d_u32).wrapping_add(e_u32); self.value = Word::from(expected); let a = a_u32.to_le_bytes(); diff --git a/core/src/operations/and.rs b/crates/core/machine/src/operations/and.rs similarity index 87% rename from core/src/operations/and.rs rename to crates/core/machine/src/operations/and.rs index 1eb5cb42ea..5aaae62013 100644 --- a/core/src/operations/and.rs +++ b/crates/core/machine/src/operations/and.rs @@ -1,13 +1,12 @@ -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, +}; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; /// A set of columns needed to compute the and of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] diff --git a/core/src/operations/baby_bear_range.rs b/crates/core/machine/src/operations/baby_bear_range.rs similarity index 89% rename from core/src/operations/baby_bear_range.rs rename to crates/core/machine/src/operations/baby_bear_range.rs index 7e1ad0ef42..17674b6491 100644 --- a/core/src/operations/baby_bear_range.rs +++ b/crates/core/machine/src/operations/baby_bear_range.rs @@ -3,8 +3,7 @@ use std::array; use p3_air::AirBuilder; use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; - -use crate::stark::SP1AirBuilder; +use sp1_stark::air::SP1AirBuilder; #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] #[repr(C)] @@ -46,20 +45,17 @@ impl BabyBearBitDecomposition { } // Assert that bits2num(bits) == value. - builder - .when(is_real.clone()) - .assert_eq(reconstructed_value, value); + builder.when(is_real.clone()).assert_eq(reconstructed_value, value); // Range check that value is less than baby bear modulus. To do this, it is sufficient - // to just do comparisons for the most significant byte. BabyBear's modulus is (in big endian binary) - // 01111000_00000000_00000000_00000001. So we need to check the following conditions: + // to just do comparisons for the most significant byte. BabyBear's modulus is (in big + // endian binary) 01111000_00000000_00000000_00000001. So we need to check the + // following conditions: // 1) if most_sig_byte > 01111000, then fail. // 2) if most_sig_byte == 01111000, then value's lower sig bytes must all be 0. // 3) if most_sig_byte < 01111000, then pass. let most_sig_byte_decomp = &cols.bits[24..32]; - builder - .when(is_real.clone()) - .assert_zero(most_sig_byte_decomp[7]); + builder.when(is_real.clone()).assert_zero(most_sig_byte_decomp[7]); // Compute the product of the "top bits". builder.when(is_real.clone()).assert_eq( diff --git a/core/src/operations/baby_bear_word.rs b/crates/core/machine/src/operations/baby_bear_word.rs similarity index 76% rename from core/src/operations/baby_bear_word.rs rename to crates/core/machine/src/operations/baby_bear_word.rs index 2e773b3e6d..48e09b50c9 100644 --- a/core/src/operations/baby_bear_word.rs +++ b/crates/core/machine/src/operations/baby_bear_word.rs @@ -3,8 +3,7 @@ use std::array; use p3_air::AirBuilder; use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; - -use crate::{air::Word, stark::SP1AirBuilder}; +use sp1_stark::{air::SP1AirBuilder, Word}; /// A set of columns needed to compute the add of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -41,28 +40,22 @@ impl BabyBearWordRangeChecker { is_real: AB::Expr, ) { let mut recomposed_byte = AB::Expr::zero(); - cols.most_sig_byte_decomp - .iter() - .enumerate() - .for_each(|(i, value)| { - builder.when(is_real.clone()).assert_bool(*value); - recomposed_byte = - recomposed_byte.clone() + AB::Expr::from_canonical_usize(1 << i) * *value; - }); + cols.most_sig_byte_decomp.iter().enumerate().for_each(|(i, value)| { + builder.when(is_real.clone()).assert_bool(*value); + recomposed_byte = + recomposed_byte.clone() + AB::Expr::from_canonical_usize(1 << i) * *value; + }); - builder - .when(is_real.clone()) - .assert_eq(recomposed_byte, value[3]); + builder.when(is_real.clone()).assert_eq(recomposed_byte, value[3]); // Range check that value is less than baby bear modulus. To do this, it is sufficient - // to just do comparisons for the most significant byte. BabyBear's modulus is (in big endian binary) - // 01111000_00000000_00000000_00000001. So we need to check the following conditions: + // to just do comparisons for the most significant byte. BabyBear's modulus is (in big + // endian binary) 01111000_00000000_00000000_00000001. So we need to check the + // following conditions: // 1) if most_sig_byte > 01111000, then fail. // 2) if most_sig_byte == 01111000, then value's lower sig bytes must all be 0. // 3) if most_sig_byte < 01111000, then pass. - builder - .when(is_real.clone()) - .assert_zero(cols.most_sig_byte_decomp[7]); + builder.when(is_real.clone()).assert_zero(cols.most_sig_byte_decomp[7]); // Compute the product of the "top bits". builder.when(is_real.clone()).assert_eq( @@ -78,10 +71,8 @@ impl BabyBearWordRangeChecker { cols.and_most_sig_byte_decomp_3_to_6 * cols.most_sig_byte_decomp[6], ); - let bottom_bits: AB::Expr = cols.most_sig_byte_decomp[0..3] - .iter() - .map(|bit| (*bit).into()) - .sum(); + let bottom_bits: AB::Expr = + cols.most_sig_byte_decomp[0..3].iter().map(|bit| (*bit).into()).sum(); builder .when(is_real.clone()) .when(cols.and_most_sig_byte_decomp_3_to_7) diff --git a/core/src/operations/field/field_den.rs b/crates/core/machine/src/operations/field/field_den.rs similarity index 88% rename from core/src/operations/field/field_den.rs rename to crates/core/machine/src/operations/field/field_den.rs index 1367a67f5d..610cbf66af 100644 --- a/core/src/operations/field/field_den.rs +++ b/crates/core/machine/src/operations/field/field_den.rs @@ -2,14 +2,16 @@ use std::fmt::Debug; use num::BigUint; use p3_field::PrimeField32; +use sp1_core_executor::events::ByteRecord; +use sp1_curves::params::{FieldParameters, Limbs}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{Polynomial, SP1AirBuilder}; -use super::params::{FieldParameters, Limbs}; -use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; -use super::util_air::eval_field_operation; -use crate::air::Polynomial; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; +use super::{ + util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}, + util_air::eval_field_operation, +}; +use crate::air::WordAirBuilder; /// A set of columns to compute `FieldDen(a, b)` where `a`, `b` are field elements. /// @@ -47,11 +49,7 @@ impl FieldDenCols { debug_assert_eq!(&den_inv * &denominator % &p, BigUint::from(1u32)); debug_assert!(result < p); - let equation_lhs = if sign { - b * &result + &result - } else { - b * &result + a - }; + let equation_lhs = if sign { b * &result + &result } else { b * &result + a }; let equation_rhs = if sign { a.clone() } else { result.clone() }; let carry = (&equation_lhs - &equation_rhs) / &p; debug_assert!(carry < p); @@ -117,14 +115,11 @@ where let p_carry = self.carry.into(); // Compute the vanishing polynomial: - // lhs(x) = sign * (b(x) * result(x) + result(x)) + (1 - sign) * (b(x) * result(x) + a(x)) - // rhs(x) = sign * a(x) + (1 - sign) * result(x) + // lhs(x) = sign * (b(x) * result(x) + result(x)) + (1 - sign) * (b(x) * result(x) + + // a(x)) rhs(x) = sign * a(x) + (1 - sign) * result(x) // lhs(x) - rhs(x) - carry(x) * p(x) - let p_equation_lhs = if sign { - &p_b * &p_result + &p_result - } else { - &p_b * &p_result + &p_a - }; + let p_equation_lhs = + if sign { &p_b * &p_result + &p_result } else { &p_b * &p_result + &p_a }; let p_equation_rhs = if sign { p_a } else { p_result }; let p_lhs_minus_rhs = &p_equation_lhs - &p_equation_rhs; @@ -165,27 +160,28 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use sp1_core_executor::{ExecutionRecord, Program}; + use sp1_curves::params::FieldParameters; + use sp1_stark::{ + air::{MachineAir, SP1AirBuilder}, + baby_bear_poseidon2::BabyBearPoseidon2, + StarkGenericConfig, + }; use super::{FieldDenCols, Limbs}; - use crate::air::MachineAir; - - use crate::operations::field::params::FieldParameters; - use crate::runtime::Program; - use crate::stark::StarkGenericConfig; - use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::BabyBearPoseidon2; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; - use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; - use core::borrow::{Borrow, BorrowMut}; - use core::mem::size_of; + use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, + }; use num::bigint::RandBigInt; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_field::AbstractField; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::Matrix; + use p3_matrix::{dense::RowMajorMatrix, Matrix}; use rand::thread_rng; + use sp1_curves::edwards::ed25519::Ed25519BaseField; use sp1_derive::AlignedBorrow; #[derive(Debug, Clone, AlignedBorrow)] @@ -204,10 +200,7 @@ mod tests { impl FieldDenChip

{ pub const fn new(sign: bool) -> Self { - Self { - sign, - _phantom: std::marker::PhantomData, - } + Self { sign, _phantom: std::marker::PhantomData } } } @@ -260,10 +253,7 @@ mod tests { // Note we do not pad the trace here because we cannot just pad with all 0s. - RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_TEST_COLS, - ) + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_TEST_COLS) } fn included(&self, _: &Self::Record) -> bool { diff --git a/core/src/operations/field/field_inner_product.rs b/crates/core/machine/src/operations/field/field_inner_product.rs similarity index 85% rename from core/src/operations/field/field_inner_product.rs rename to crates/core/machine/src/operations/field/field_inner_product.rs index 859e1642e9..c90bf035d8 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/crates/core/machine/src/operations/field/field_inner_product.rs @@ -1,17 +1,17 @@ use std::fmt::Debug; -use num::BigUint; -use num::Zero; +use num::{BigUint, Zero}; use p3_field::{AbstractField, PrimeField32}; +use sp1_core_executor::events::ByteRecord; +use sp1_curves::params::{FieldParameters, Limbs}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{Polynomial, SP1AirBuilder}; -use super::params::Limbs; -use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; -use super::util_air::eval_field_operation; -use crate::air::Polynomial; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::operations::field::params::FieldParameters; +use super::{ + util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}, + util_air::eval_field_operation, +}; +use crate::air::WordAirBuilder; /// A set of columns to compute `InnerProduct([a], [b])` where a, b are emulated elements. /// @@ -38,20 +38,13 @@ impl FieldInnerProductCols { a: &[BigUint], b: &[BigUint], ) -> BigUint { - let p_a_vec: Vec> = a - .iter() - .map(|x| P::to_limbs_field::(x).into()) - .collect(); - let p_b_vec: Vec> = b - .iter() - .map(|x| P::to_limbs_field::(x).into()) - .collect(); + let p_a_vec: Vec> = + a.iter().map(|x| P::to_limbs_field::(x).into()).collect(); + let p_b_vec: Vec> = + b.iter().map(|x| P::to_limbs_field::(x).into()).collect(); let modulus = &P::modulus(); - let inner_product = a - .iter() - .zip(b.iter()) - .fold(BigUint::zero(), |acc, (c, d)| acc + c * d); + let inner_product = a.iter().zip(b.iter()).fold(BigUint::zero(), |acc, (c, d)| acc + c * d); let result = &(&inner_product % modulus); let carry = &((&inner_product - result) / modulus); @@ -67,9 +60,7 @@ impl FieldInnerProductCols { let p_inner_product = p_a_vec .into_iter() .zip(p_b_vec) - .fold(Polynomial::::new(vec![F::zero()]), |acc, (c, d)| { - acc + &c * &d - }); + .fold(Polynomial::::new(vec![F::zero()]), |acc, (c, d)| acc + &c * &d); let p_vanishing = p_inner_product - &p_result - &p_carry * &p_modulus; assert_eq!(p_vanishing.degree(), P::NB_WITNESS_LIMBS); @@ -163,28 +154,26 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use sp1_core_executor::{ExecutionRecord, Program}; + use sp1_curves::params::FieldParameters; + use sp1_stark::air::{MachineAir, SP1AirBuilder}; use super::{FieldInnerProductCols, Limbs}; - use crate::air::MachineAir; - - use crate::operations::field::params::FieldParameters; - use crate::runtime::Program; - use crate::stark::StarkGenericConfig; - use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; - use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; - use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; - use core::borrow::{Borrow, BorrowMut}; - use core::mem::size_of; + use crate::utils::{pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify}; + use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, + }; use num::bigint::RandBigInt; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_field::AbstractField; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::Matrix; + use p3_matrix::{dense::RowMajorMatrix, Matrix}; use rand::thread_rng; + use sp1_curves::edwards::ed25519::Ed25519BaseField; use sp1_derive::AlignedBorrow; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { @@ -201,9 +190,7 @@ mod tests { impl FieldIpChip

{ pub const fn new() -> Self { - Self { - _phantom: std::marker::PhantomData, - } + Self { _phantom: std::marker::PhantomData } } } @@ -249,10 +236,8 @@ mod tests { }) .collect::>(); // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_TEST_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_TEST_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); diff --git a/core/src/operations/field/field_op.rs b/crates/core/machine/src/operations/field/field_op.rs similarity index 73% rename from core/src/operations/field/field_op.rs rename to crates/core/machine/src/operations/field/field_op.rs index 848099b7f5..b2120dad99 100644 --- a/core/src/operations/field/field_op.rs +++ b/crates/core/machine/src/operations/field/field_op.rs @@ -1,26 +1,22 @@ use std::fmt::Debug; +use crate::air::WordAirBuilder; use num::{BigUint, Zero}; + use p3_air::AirBuilder; use p3_field::PrimeField32; + +use sp1_core_executor::events::{ByteRecord, FieldOperation}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{Polynomial, SP1AirBuilder}; -use super::params::{FieldParameters, Limbs}; -use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; -use super::util_air::eval_field_operation; -use crate::air::Polynomial; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use typenum::Unsigned; +use super::{ + util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}, + util_air::eval_field_operation, +}; +use sp1_curves::params::{FieldParameters, Limbs}; -/// Airthmetic operation for emulating modular arithmetic. -#[derive(PartialEq, Copy, Clone, Debug)] -pub enum FieldOperation { - Add, - Mul, - Sub, - Div, -} +use typenum::Unsigned; /// A set of columns to compute an emulated modular arithmetic operation. /// @@ -69,12 +65,10 @@ impl FieldOpCols { } // Here we have special logic for p_modulus because to_limbs_field only works for numbers in - // the field, but modulus can == the field modulus so it can have 1 extra limb (ex. uint256). - let p_modulus_limbs = modulus - .to_bytes_le() - .iter() - .map(|x| F::from_canonical_u8(*x)) - .collect::>(); + // the field, but modulus can == the field modulus so it can have 1 extra limb (ex. + // uint256). + let p_modulus_limbs = + modulus.to_bytes_le().iter().map(|x| F::from_canonical_u8(*x)).collect::>(); let p_modulus: Polynomial = p_modulus_limbs.iter().into(); let p_result: Polynomial = P::to_limbs_field::(&result).into(); let p_carry: Polynomial = P::to_limbs_field::(&carry).into(); @@ -121,22 +115,18 @@ impl FieldOpCols { ) -> BigUint { if b == &BigUint::zero() && op == FieldOperation::Div { // Division by 0 is allowed only when dividing 0 so that padded rows can be all 0. - assert_eq!( - *a, - BigUint::zero(), - "division by zero is allowed only when dividing zero" - ); + assert_eq!(*a, BigUint::zero(), "division by zero is allowed only when dividing zero"); } let result = match op { // If doing the subtraction operation, a - b = result, equivalent to a = result + b. FieldOperation::Sub => { let result = (modulus.clone() + a - b) % modulus; - // We populate the carry, witness_low, witness_high as if we were doing an addition with result + b. - // But we populate `result` with the actual result of the subtraction because those columns are expected - // to contain the result by the user. - // Note that this reversal means we have to flip result, a correspondingly in - // the `eval` function. + // We populate the carry, witness_low, witness_high as if we were doing an addition + // with result + b. But we populate `result` with the actual result + // of the subtraction because those columns are expected to contain + // the result by the user. Note that this reversal means we have to + // flip result, a correspondingly in the `eval` function. self.populate_carry_and_witness(&result, b, FieldOperation::Add, modulus); self.result = P::to_limbs_field::(&result); result @@ -148,10 +138,11 @@ impl FieldOpCols { let result = (a * b.modpow(&(modulus.clone() - 2u32), &modulus.clone())) % modulus.clone(); - // We populate the carry, witness_low, witness_high as if we were doing a multiplication - // with result * b. But we populate `result` with the actual result of the - // multiplication because those columns are expected to contain the result by the user. - // Note that this reversal means we have to flip result, a correspondingly in the `eval` + // We populate the carry, witness_low, witness_high as if we were doing a + // multiplication with result * b. But we populate `result` with the + // actual result of the multiplication because those columns are + // expected to contain the result by the user. Note that this + // reversal means we have to flip result, a correspondingly in the `eval` // function. self.populate_carry_and_witness(&result, b, FieldOperation::Mul, modulus); self.result = P::to_limbs_field::(&result); @@ -169,7 +160,8 @@ impl FieldOpCols { result } - /// Populate these columns without a specified modulus (will use the modulus of the field parameters). + /// Populate these columns without a specified modulus (will use the modulus of the field + /// parameters). pub fn populate( &mut self, record: &mut impl ByteRecord, @@ -184,6 +176,54 @@ impl FieldOpCols { } impl FieldOpCols { + /// Allows an evaluation over opetations specified by boolean flags. + #[allow(clippy::too_many_arguments)] + pub fn eval_variable>( + &self, + builder: &mut AB, + a: &(impl Into> + Clone), + b: &(impl Into> + Clone), + modulus: &(impl Into> + Clone), + is_add: impl Into + Clone, + is_sub: impl Into + Clone, + is_mul: impl Into + Clone, + is_div: impl Into + Clone, + shard: impl Into + Clone, + channel: impl Into + Clone, + is_real: impl Into + Clone, + ) where + V: Into, + Limbs: Copy, + { + let p_a_param: Polynomial = (a).clone().into(); + let p_b: Polynomial = (b).clone().into(); + let p_res_param: Polynomial = self.result.into(); + + let is_add: AB::Expr = is_add.into(); + let is_sub: AB::Expr = is_sub.into(); + let is_mul: AB::Expr = is_mul.into(); + let is_div: AB::Expr = is_div.into(); + + let p_result = p_res_param.clone() * (is_add.clone() + is_mul.clone()) + + p_a_param.clone() * (is_sub.clone() + is_div.clone()); + + let p_add = p_a_param.clone() + p_b.clone(); + let p_sub = p_res_param.clone() + p_b.clone(); + let p_mul = p_a_param.clone() * p_b.clone(); + let p_div = p_res_param * p_b.clone(); + let p_op = p_add * is_add + p_sub * is_sub + p_mul * is_mul + p_div * is_div; + + self.eval_with_polynomials( + builder, + p_op, + modulus.clone(), + p_result, + shard, + channel, + is_real, + ); + } + #[allow(clippy::too_many_arguments)] pub fn eval_with_modulus>( &self, @@ -201,17 +241,44 @@ impl FieldOpCols { { let p_a_param: Polynomial = (a).clone().into(); let p_b: Polynomial = (b).clone().into(); - let p_modulus: Polynomial = (modulus).clone().into(); let (p_a, p_result): (Polynomial<_>, Polynomial<_>) = match op { FieldOperation::Add | FieldOperation::Mul => (p_a_param, self.result.into()), FieldOperation::Sub | FieldOperation::Div => (self.result.into(), p_a_param), }; - let p_carry: Polynomial<::Expr> = self.carry.into(); - let p_op = match op { + let p_op: Polynomial<::Expr> = match op { FieldOperation::Add | FieldOperation::Sub => p_a + p_b, FieldOperation::Mul | FieldOperation::Div => p_a * p_b, }; + self.eval_with_polynomials( + builder, + p_op, + modulus.clone(), + p_result, + shard, + channel, + is_real, + ); + } + + #[allow(clippy::too_many_arguments)] + pub fn eval_with_polynomials>( + &self, + builder: &mut AB, + op: impl Into>, + modulus: impl Into>, + result: impl Into>, + shard: impl Into + Clone, + channel: impl Into + Clone, + is_real: impl Into + Clone, + ) where + V: Into, + Limbs: Copy, + { + let p_op: Polynomial = op.into(); + let p_result: Polynomial = result.into(); + let p_modulus: Polynomial = modulus.into(); + let p_carry: Polynomial<::Expr> = self.carry.into(); let p_op_minus_result: Polynomial = p_op - &p_result; let p_vanishing = p_op_minus_result - &(&p_carry * &p_modulus); let p_witness_low = self.witness_low.0.iter().into(); @@ -269,31 +336,29 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use sp1_core_executor::{ExecutionRecord, Program}; + use sp1_curves::params::FieldParameters; + use sp1_stark::{ + air::{MachineAir, SP1AirBuilder}, + StarkGenericConfig, + }; use super::{FieldOpCols, FieldOperation, Limbs}; - use crate::air::MachineAir; - - use crate::bytes::event::ByteRecord; - use crate::operations::field::params::FieldParameters; - use crate::runtime::Program; - use crate::stark::StarkGenericConfig; - use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; - use crate::utils::{ - pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify, - BabyBearPoseidon2, - }; - use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; + use crate::utils::{pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify}; use core::borrow::{Borrow, BorrowMut}; use num::bigint::RandBigInt; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_field::AbstractField; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::Matrix; + use p3_matrix::{dense::RowMajorMatrix, Matrix}; use rand::thread_rng; + use sp1_core_executor::events::ByteRecord; + use sp1_curves::{ + edwards::ed25519::Ed25519BaseField, weierstrass::secp256k1::Secp256k1BaseField, + }; use sp1_derive::AlignedBorrow; + use sp1_stark::baby_bear_poseidon2::BabyBearPoseidon2; use std::mem::size_of; #[derive(AlignedBorrow, Debug, Clone)] @@ -312,10 +377,7 @@ mod tests { impl FieldOpChip

{ pub const fn new(operation: FieldOperation) -> Self { - Self { - operation, - _phantom: std::marker::PhantomData, - } + Self { operation, _phantom: std::marker::PhantomData } } } @@ -361,17 +423,14 @@ mod tests { let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); cols.a = P::to_limbs_field::(a); cols.b = P::to_limbs_field::(b); - cols.a_op_b - .populate(&mut blu_events, 1, 0, a, b, self.operation); + cols.a_op_b.populate(&mut blu_events, 1, 0, a, b, self.operation); output.add_byte_lookup_events(blu_events); row }) .collect::>(); // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_TEST_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_TEST_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); @@ -413,13 +472,7 @@ mod tests { #[test] fn generate_trace() { - for op in [ - FieldOperation::Add, - FieldOperation::Mul, - FieldOperation::Sub, - ] - .iter() - { + for op in [FieldOperation::Add, FieldOperation::Mul, FieldOperation::Sub].iter() { println!("op: {:?}", op); let chip: FieldOpChip = FieldOpChip::new(*op); let shard = ExecutionRecord::default(); @@ -433,13 +486,9 @@ mod tests { fn prove_babybear() { let config = BabyBearPoseidon2::new(); - for op in [ - FieldOperation::Add, - FieldOperation::Sub, - FieldOperation::Mul, - FieldOperation::Div, - ] - .iter() + for op in + [FieldOperation::Add, FieldOperation::Sub, FieldOperation::Mul, FieldOperation::Div] + .iter() { println!("op: {:?}", op); diff --git a/core/src/operations/field/field_sqrt.rs b/crates/core/machine/src/operations/field/field_sqrt.rs similarity index 85% rename from core/src/operations/field/field_sqrt.rs rename to crates/core/machine/src/operations/field/field_sqrt.rs index 0f1e7f69e0..50d2cc4729 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/crates/core/machine/src/operations/field/field_sqrt.rs @@ -3,15 +3,17 @@ use std::fmt::Debug; use num::BigUint; use p3_air::AirBuilder; use p3_field::PrimeField32; +use sp1_curves::params::{limbs_from_vec, FieldParameters, Limbs}; use sp1_derive::AlignedBorrow; -use super::field_op::FieldOpCols; -use super::params::{limbs_from_vec, Limbs}; -use super::range::FieldLtCols; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::bytes::{ByteLookupEvent, ByteOpcode}; -use crate::operations::field::params::FieldParameters; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + ByteOpcode, +}; +use sp1_stark::air::SP1AirBuilder; + +use super::{field_op::FieldOpCols, range::FieldLtCols}; +use crate::air::WordAirBuilder; use p3_field::AbstractField; /// A set of columns to compute the square root in emulated arithmetic. @@ -50,20 +52,14 @@ impl FieldSqrtCols { let sqrt = sqrt_fn(a); // Use FieldOpCols to compute result * result. - let sqrt_squared = self.multiplication.populate( - record, - shard, - channel, - &sqrt, - &sqrt, - super::field_op::FieldOperation::Mul, - ); + let sqrt_squared = + self.multiplication.populate(record, shard, channel, &sqrt, &sqrt, FieldOperation::Mul); // If the result is indeed the square root of a, then result * result = a. assert_eq!(sqrt_squared, a.clone()); - // This is a hack to save a column in FieldSqrtCols. We will receive the value a again in the - // eval function, so we'll overwrite it with the sqrt. + // This is a hack to save a column in FieldSqrtCols. We will receive the value a again in + // the eval function, so we'll overwrite it with the sqrt. self.multiplication.result = P::to_limbs_field::(&sqrt); // Populate the range columns. @@ -129,7 +125,7 @@ where builder, &sqrt, &sqrt, - super::field_op::FieldOperation::Mul, + FieldOperation::Mul, shard.clone(), channel.clone(), is_real.clone(), @@ -174,29 +170,27 @@ mod tests { use num::{BigUint, One, Zero}; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - - use super::{FieldSqrtCols, Limbs}; - - use crate::air::MachineAir; - - use crate::bytes::event::ByteRecord; - use crate::operations::field::params::FieldParameters; - use crate::runtime::Program; - use crate::stark::StarkGenericConfig; - use crate::utils::ec::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; - use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; - use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; - use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; - use core::borrow::{Borrow, BorrowMut}; - use core::mem::size_of; + use sp1_core_executor::{ExecutionRecord, Program}; + use sp1_curves::params::{FieldParameters, Limbs}; + use sp1_stark::air::{MachineAir, SP1AirBuilder}; + + use crate::utils::{pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify}; + use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, + }; use num::bigint::RandBigInt; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_field::AbstractField; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::Matrix; + use p3_matrix::{dense::RowMajorMatrix, Matrix}; use rand::thread_rng; + use sp1_core_executor::events::ByteRecord; + use sp1_curves::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; use sp1_derive::AlignedBorrow; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; + + use super::FieldSqrtCols; #[derive(AlignedBorrow, Debug)] pub struct TestCols { @@ -212,9 +206,7 @@ mod tests { impl EdSqrtChip

{ pub const fn new() -> Self { - Self { - _phantom: std::marker::PhantomData, - } + Self { _phantom: std::marker::PhantomData } } } @@ -260,10 +252,8 @@ mod tests { }) .collect::>(); // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_TEST_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_TEST_COLS); // Pad the trace to a power of two. pad_to_power_of_two::(&mut trace.values); diff --git a/core/src/operations/field/mod.rs b/crates/core/machine/src/operations/field/mod.rs similarity index 87% rename from core/src/operations/field/mod.rs rename to crates/core/machine/src/operations/field/mod.rs index d08b90c2ec..5a4f1b4a5e 100644 --- a/core/src/operations/field/mod.rs +++ b/crates/core/machine/src/operations/field/mod.rs @@ -2,7 +2,7 @@ pub mod field_den; pub mod field_inner_product; pub mod field_op; pub mod field_sqrt; -pub mod params; +// pub mod params; pub mod range; pub mod util; pub mod util_air; diff --git a/core/src/operations/field/params.rs b/crates/core/machine/src/operations/field/params.rs similarity index 94% rename from core/src/operations/field/params.rs rename to crates/core/machine/src/operations/field/params.rs index 3a34764e18..c6bcd8fc27 100644 --- a/core/src/operations/field/params.rs +++ b/crates/core/machine/src/operations/field/params.rs @@ -5,6 +5,7 @@ use std::slice::Iter; use serde::de::DeserializeOwned; use serde::Serialize; +use sp1_stark::air::Polynomial; use typenum::Unsigned; use typenum::{U2, U4}; @@ -14,8 +15,7 @@ use num::BigUint; use p3_field::Field; -use crate::air::Polynomial; -use crate::utils::ec::utils::biguint_from_limbs; +use sp1_curves::utils::biguint_from_limbs; pub const NB_BITS_PER_LIMB: usize = 8; @@ -157,12 +157,6 @@ impl + Clone, N: ArrayLength, Expr: Clone> From> } } -impl<'a, Var: Into + Clone, Expr: Clone> From> for Polynomial { - fn from(value: Iter<'a, Var>) -> Self { - Polynomial::from_coefficients(&value.map(|x| (*x).clone().into()).collect::>()) - } -} - impl From> for Limbs { fn from(value: Polynomial) -> Self { let inner = value.as_coefficients().try_into().unwrap(); diff --git a/core/src/operations/field/range.rs b/crates/core/machine/src/operations/field/range.rs similarity index 87% rename from core/src/operations/field/range.rs rename to crates/core/machine/src/operations/field/range.rs index 3f652021a1..0f6dce4144 100644 --- a/core/src/operations/field/range.rs +++ b/crates/core/machine/src/operations/field/range.rs @@ -1,24 +1,19 @@ use itertools::izip; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, +}; +use sp1_stark::air::{BaseAirBuilder, Polynomial, SP1AirBuilder}; use std::fmt::Debug; use num::BigUint; use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::PrimeField32; +use p3_field::{AbstractField, PrimeField32}; +use sp1_curves::params::{FieldParameters, Limbs}; use sp1_derive::AlignedBorrow; -use crate::air::BaseAirBuilder; -use crate::{ - air::Polynomial, - bytes::{event::ByteRecord, ByteLookupEvent, ByteOpcode}, - stark::SP1AirBuilder, -}; - -use super::params::FieldParameters; -use super::params::Limbs; - /// Operation columns for verifying that `lhs < rhs`. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] @@ -47,11 +42,9 @@ impl FieldLtCols { let mut byte_flags = vec![0u8; P::NB_LIMBS]; - for (byte, modulus_byte, flag) in izip!( - value_limbs.iter().rev(), - modulus.iter().rev(), - byte_flags.iter_mut().rev() - ) { + for (byte, modulus_byte, flag) in + izip!(value_limbs.iter().rev(), modulus.iter().rev(), byte_flags.iter_mut().rev()) + { assert!(byte <= modulus_byte); if byte < modulus_byte { *flag = 1; @@ -143,12 +136,8 @@ impl FieldLtCols { .assert_eq(lhs_byte.clone(), rhs_byte.clone()); } - builder - .when(is_real.clone()) - .assert_eq(self.lhs_comparison_byte, lhs_comparison_byte); - builder - .when(is_real.clone()) - .assert_eq(self.rhs_comparison_byte, rhs_comparison_byte); + builder.when(is_real.clone()).assert_eq(self.lhs_comparison_byte, lhs_comparison_byte); + builder.when(is_real.clone()).assert_eq(self.rhs_comparison_byte, rhs_comparison_byte); // Send the comparison interaction. builder.send_byte( diff --git a/core/src/operations/field/util.rs b/crates/core/machine/src/operations/field/util.rs similarity index 92% rename from core/src/operations/field/util.rs rename to crates/core/machine/src/operations/field/util.rs index 079f90d79c..094e91a812 100644 --- a/core/src/operations/field/util.rs +++ b/crates/core/machine/src/operations/field/util.rs @@ -1,7 +1,6 @@ use num::BigUint; use p3_field::PrimeField32; - -use crate::air::Polynomial; +use sp1_stark::air::Polynomial; fn biguint_to_field(num: BigUint) -> F { let mut x = F::zero(); @@ -62,11 +61,7 @@ pub fn compute_root_quotient_and_shift( #[inline] pub fn split_u16_limbs_to_u8_limbs(slice: &[F]) -> (Vec, Vec) { ( - slice - .iter() - .map(|x| x.as_canonical_u64() as u8) - .map(|x| F::from_canonical_u8(x)) - .collect(), + slice.iter().map(|x| x.as_canonical_u64() as u8).map(|x| F::from_canonical_u8(x)).collect(), slice .iter() .map(|x| (x.as_canonical_u64() >> 8) as u8) diff --git a/core/src/operations/field/util_air.rs b/crates/core/machine/src/operations/field/util_air.rs similarity index 91% rename from core/src/operations/field/util_air.rs rename to crates/core/machine/src/operations/field/util_air.rs index 54ae64216d..46b53bb0aa 100644 --- a/core/src/operations/field/util_air.rs +++ b/crates/core/machine/src/operations/field/util_air.rs @@ -1,8 +1,6 @@ use p3_field::AbstractField; - -use crate::air::Polynomial; -use crate::air::SP1AirBuilder; -use crate::operations::field::params::FieldParameters; +use sp1_curves::params::FieldParameters; +use sp1_stark::air::{Polynomial, SP1AirBuilder}; pub fn eval_field_operation( builder: &mut AB, diff --git a/core/src/operations/fixed_rotate_right.rs b/crates/core/machine/src/operations/fixed_rotate_right.rs similarity index 93% rename from core/src/operations/fixed_rotate_right.rs rename to crates/core/machine/src/operations/fixed_rotate_right.rs index 3979925311..5f97ec2923 100644 --- a/core/src/operations/fixed_rotate_right.rs +++ b/crates/core/machine/src/operations/fixed_rotate_right.rs @@ -1,14 +1,13 @@ -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; use crate::bytes::utils::shr_carry; -use crate::bytes::ByteLookupEvent; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; /// A set of columns needed to compute `rotateright` of a word with a fixed offset R. /// @@ -154,9 +153,6 @@ impl FixedRotateRightOperation { } // For the first byte, we didn't know the last carry so compute the rotated byte here. - builder.assert_eq( - cols.value[WORD_SIZE - 1], - first_shift + last_carry * carry_multiplier, - ); + builder.assert_eq(cols.value[WORD_SIZE - 1], first_shift + last_carry * carry_multiplier); } } diff --git a/core/src/operations/fixed_shift_right.rs b/crates/core/machine/src/operations/fixed_shift_right.rs similarity index 95% rename from core/src/operations/fixed_shift_right.rs rename to crates/core/machine/src/operations/fixed_shift_right.rs index 7ec611faff..d77acb9b42 100644 --- a/core/src/operations/fixed_shift_right.rs +++ b/crates/core/machine/src/operations/fixed_shift_right.rs @@ -1,14 +1,13 @@ -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, +}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; use crate::bytes::utils::shr_carry; -use crate::bytes::ByteLookupEvent; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; /// A set of columns needed to compute `>>` of a word with a fixed offset R. /// diff --git a/core/src/operations/is_equal_word.rs b/crates/core/machine/src/operations/is_equal_word.rs similarity index 97% rename from core/src/operations/is_equal_word.rs rename to crates/core/machine/src/operations/is_equal_word.rs index fb5763079a..4ba6e60441 100644 --- a/core/src/operations/is_equal_word.rs +++ b/crates/core/machine/src/operations/is_equal_word.rs @@ -1,9 +1,8 @@ use p3_field::Field; use sp1_derive::AlignedBorrow; +use sp1_stark::{air::SP1AirBuilder, Word}; use super::IsZeroWordOperation; -use crate::air::SP1AirBuilder; -use crate::air::Word; /// A set of columns needed to compute the equality of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] diff --git a/core/src/operations/is_zero.rs b/crates/core/machine/src/operations/is_zero.rs similarity index 87% rename from core/src/operations/is_zero.rs rename to crates/core/machine/src/operations/is_zero.rs index 67f183bb66..74ecfbef4f 100644 --- a/core/src/operations/is_zero.rs +++ b/crates/core/machine/src/operations/is_zero.rs @@ -5,11 +5,10 @@ //! The idea is that 1 - input * inverse is exactly the boolean value indicating whether the input //! is 0. use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; -use crate::air::SP1AirBuilder; +use sp1_stark::air::SP1AirBuilder; /// A set of columns needed to compute whether the given word is 0. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -59,15 +58,10 @@ impl IsZeroOperation { // If the input is 0, then any product involving it is 0. If it is nonzero and its inverse // is correctly set, then the product is 1. let is_zero = one.clone() - cols.inverse * a.clone(); - builder - .when(is_real.clone()) - .assert_eq(is_zero, cols.result); + builder.when(is_real.clone()).assert_eq(is_zero, cols.result); builder.when(is_real.clone()).assert_bool(cols.result); // If the result is 1, then the input is 0. - builder - .when(is_real.clone()) - .when(cols.result) - .assert_zero(a.clone()); + builder.when(is_real.clone()).when(cols.result).assert_zero(a.clone()); } } diff --git a/core/src/operations/is_zero_word.rs b/crates/core/machine/src/operations/is_zero_word.rs similarity index 93% rename from core/src/operations/is_zero_word.rs rename to crates/core/machine/src/operations/is_zero_word.rs index ca3445d25c..946fab6fb0 100644 --- a/core/src/operations/is_zero_word.rs +++ b/crates/core/machine/src/operations/is_zero_word.rs @@ -5,11 +5,10 @@ use p3_air::AirBuilder; use p3_field::Field; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; use super::IsZeroOperation; -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::disassembler::WORD_SIZE; /// A set of columns needed to compute whether the given word is 0. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -79,9 +78,6 @@ impl IsZeroWordOperation { cols.is_upper_half_zero, cols.is_zero_byte[2].result * cols.is_zero_byte[3].result, ); - builder_is_real.assert_eq( - cols.result, - cols.is_lower_half_zero * cols.is_upper_half_zero, - ); + builder_is_real.assert_eq(cols.result, cols.is_lower_half_zero * cols.is_upper_half_zero); } } diff --git a/core/src/operations/lt.rs b/crates/core/machine/src/operations/lt.rs similarity index 92% rename from core/src/operations/lt.rs rename to crates/core/machine/src/operations/lt.rs index 619e96fc9b..2f531f18c8 100644 --- a/core/src/operations/lt.rs +++ b/crates/core/machine/src/operations/lt.rs @@ -1,16 +1,14 @@ use itertools::izip; use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::PrimeField32; +use p3_field::{AbstractField, PrimeField32}; -use sp1_derive::AlignedBorrow; - -use crate::air::BaseAirBuilder; -use crate::{ - bytes::{event::ByteRecord, ByteLookupEvent, ByteOpcode}, - stark::SP1AirBuilder, +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, }; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, SP1AirBuilder}; /// Operation columns for verifying that an element is within the range `[0, modulus)`. #[derive(Debug, Clone, Copy, AlignedBorrow)] @@ -127,12 +125,8 @@ impl AssertLtColsBytes { .assert_eq(a_byte.clone(), b_byte.clone()); } - builder - .when(is_real.clone()) - .assert_eq(self.a_comparison_byte, first_lt_byte); - builder - .when(is_real.clone()) - .assert_eq(self.b_comparison_byte, b_comparison_byte); + builder.when(is_real.clone()).assert_eq(self.a_comparison_byte, first_lt_byte); + builder.when(is_real.clone()).assert_eq(self.b_comparison_byte, b_comparison_byte); // Send the comparison interaction. builder.send_byte( @@ -241,11 +235,7 @@ impl AssertLtColsBits { .assert_eq(a_bit.clone(), b_bit.clone()); } - builder - .when(is_real.clone()) - .assert_eq(a_comparison_bit, AB::F::zero()); - builder - .when(is_real.clone()) - .assert_eq(b_comparison_bit, AB::F::one()); + builder.when(is_real.clone()).assert_eq(a_comparison_bit, AB::F::zero()); + builder.when(is_real.clone()).assert_eq(b_comparison_bit, AB::F::one()); } } diff --git a/core/src/operations/mod.rs b/crates/core/machine/src/operations/mod.rs similarity index 100% rename from core/src/operations/mod.rs rename to crates/core/machine/src/operations/mod.rs diff --git a/core/src/operations/not.rs b/crates/core/machine/src/operations/not.rs similarity index 88% rename from core/src/operations/not.rs rename to crates/core/machine/src/operations/not.rs index 84b6b32ffe..bb09ff58e4 100644 --- a/core/src/operations/not.rs +++ b/crates/core/machine/src/operations/not.rs @@ -1,13 +1,9 @@ use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; +use sp1_core_executor::{events::ByteRecord, ByteOpcode}; use sp1_derive::AlignedBorrow; - -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; /// A set of columns needed to compute the not of a word. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] diff --git a/core/src/operations/or.rs b/crates/core/machine/src/operations/or.rs similarity index 84% rename from core/src/operations/or.rs rename to crates/core/machine/src/operations/or.rs index 7f2e78b3b9..fb4a675820 100644 --- a/core/src/operations/or.rs +++ b/crates/core/machine/src/operations/or.rs @@ -1,13 +1,8 @@ -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; +use sp1_core_executor::{events::ByteRecord, ByteOpcode, ExecutionRecord}; use sp1_derive::AlignedBorrow; - -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; -use crate::runtime::ExecutionRecord; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; /// A set of columns needed to compute the or of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] diff --git a/core/src/operations/xor.rs b/crates/core/machine/src/operations/xor.rs similarity index 87% rename from core/src/operations/xor.rs rename to crates/core/machine/src/operations/xor.rs index 003ce48c2f..93fa41ac44 100644 --- a/core/src/operations/xor.rs +++ b/crates/core/machine/src/operations/xor.rs @@ -1,13 +1,11 @@ -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord}, + ByteOpcode, +}; use sp1_derive::AlignedBorrow; - -use crate::air::SP1AirBuilder; -use crate::air::Word; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::bytes::ByteOpcode; -use crate::disassembler::WORD_SIZE; +use sp1_primitives::consts::WORD_SIZE; +use sp1_stark::{air::SP1AirBuilder, Word}; /// A set of columns needed to compute the xor of two words. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] diff --git a/core/src/program/mod.rs b/crates/core/machine/src/program/mod.rs similarity index 90% rename from core/src/program/mod.rs rename to crates/core/machine/src/program/mod.rs index a54f8e0ad1..dc8daf2d0f 100644 --- a/core/src/program/mod.rs +++ b/crates/core/machine/src/program/mod.rs @@ -1,19 +1,21 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use std::collections::HashMap; +use crate::air::ProgramAirBuilder; use p3_air::{Air, BaseAir, PairBuilder}; use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ExecutionRecord, Program}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{MachineAir, SP1AirBuilder}; -use crate::air::MachineAir; -use crate::air::SP1AirBuilder; -use crate::cpu::columns::InstructionCols; -use crate::cpu::columns::OpcodeSelectorCols; -use crate::runtime::{ExecutionRecord, Program}; -use crate::utils::pad_to_power_of_two; +use crate::{ + cpu::columns::{InstructionCols, OpcodeSelectorCols}, + utils::pad_to_power_of_two, +}; /// The number of preprocessed program columns. pub const NUM_PROGRAM_PREPROCESSED_COLS: usize = size_of::>(); @@ -108,10 +110,7 @@ impl MachineAir for ProgramChip { let mut instruction_counts = HashMap::new(); input.cpu_events.iter().for_each(|event| { let pc = event.pc; - instruction_counts - .entry(pc) - .and_modify(|count| *count += 1) - .or_insert(1); + instruction_counts.entry(pc).and_modify(|count| *count += 1).or_insert(1); }); let rows = input @@ -186,12 +185,10 @@ mod tests { use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; + use sp1_core_executor::{ExecutionRecord, Instruction, Opcode, Program}; + use sp1_stark::air::MachineAir; - use crate::{ - air::MachineAir, - program::ProgramChip, - runtime::{ExecutionRecord, Instruction, Opcode, Program}, - }; + use crate::program::ProgramChip; #[test] fn generate_trace() { diff --git a/crates/core/machine/src/riscv/cost.rs b/crates/core/machine/src/riscv/cost.rs new file mode 100644 index 0000000000..685e683711 --- /dev/null +++ b/crates/core/machine/src/riscv/cost.rs @@ -0,0 +1,195 @@ +use p3_baby_bear::BabyBear; +use sp1_core_executor::{syscalls::SyscallCode, ExecutionReport, Opcode}; + +use crate::riscv::RiscvAirDiscriminants; + +use super::RiscvAir; + +pub trait CostEstimator { + /// Estimates the trace area of the execution. + fn estimate_area(&self) -> u64; + + /// Estimates the proving cost of the execution in terms of "gas". + /// + /// The gas is defined as the trace area divided by the lowerbound per cpu cycle. + /// + /// NOTE: This is an approximation and may not be accurate. For example, it does not currently + /// account for dependencies. + fn estimate_gas(&self) -> u64 { + let costs = RiscvAir::::costs(); + let cpu_gas = costs[&RiscvAirDiscriminants::Cpu]; + let total_gas = self.estimate_area(); + total_gas / cpu_gas + } +} + +impl CostEstimator for ExecutionReport { + fn estimate_area(&self) -> u64 { + let mut total_area = 0; + let mut total_chips = 3; + let (chips, costs) = RiscvAir::::get_chips_and_costs(); + + let cpu_events = self.total_instruction_count(); + total_area += (cpu_events as u64) * costs[&RiscvAirDiscriminants::Cpu]; + total_chips += 1; + + let sha_extend_events = *self.syscall_counts.get(&SyscallCode::SHA_EXTEND).unwrap_or(&0); + total_area += (sha_extend_events as u64) * costs[&RiscvAirDiscriminants::Sha256Extend]; + total_chips += 1; + + let sha_compress_events = + *self.syscall_counts.get(&SyscallCode::SHA_COMPRESS).unwrap_or(&0); + total_area += (sha_compress_events as u64) * costs[&RiscvAirDiscriminants::Sha256Compress]; + total_chips += 1; + + let ed_add_events = *self.syscall_counts.get(&SyscallCode::ED_ADD).unwrap_or(&0); + total_area += (ed_add_events as u64) * costs[&RiscvAirDiscriminants::Ed25519Add]; + total_chips += 1; + + let ed_decompress_events = + *self.syscall_counts.get(&SyscallCode::ED_DECOMPRESS).unwrap_or(&0); + total_area += + (ed_decompress_events as u64) * costs[&RiscvAirDiscriminants::Ed25519Decompress]; + total_chips += 1; + + let k256_decompress_events = + *self.syscall_counts.get(&SyscallCode::SECP256K1_DECOMPRESS).unwrap_or(&0); + total_area += + (k256_decompress_events as u64) * costs[&RiscvAirDiscriminants::K256Decompress]; + total_chips += 1; + + let secp256k1_add_events = + *self.syscall_counts.get(&SyscallCode::SECP256K1_ADD).unwrap_or(&0); + total_area += (secp256k1_add_events as u64) * costs[&RiscvAirDiscriminants::Secp256k1Add]; + total_chips += 1; + + let secp256k1_double_events = + *self.syscall_counts.get(&SyscallCode::SECP256K1_DOUBLE).unwrap_or(&0); + total_area += + (secp256k1_double_events as u64) * costs[&RiscvAirDiscriminants::Secp256k1Double]; + total_chips += 1; + + let keccak256_permute_events = + *self.syscall_counts.get(&SyscallCode::KECCAK_PERMUTE).unwrap_or(&0); + total_area += (keccak256_permute_events as u64) * costs[&RiscvAirDiscriminants::KeccakP]; + total_chips += 1; + + let bn254_add_events = *self.syscall_counts.get(&SyscallCode::BN254_ADD).unwrap_or(&0); + total_area += (bn254_add_events as u64) * costs[&RiscvAirDiscriminants::Bn254Add]; + total_chips += 1; + + let bn254_double_events = + *self.syscall_counts.get(&SyscallCode::BN254_DOUBLE).unwrap_or(&0); + total_area += (bn254_double_events as u64) * costs[&RiscvAirDiscriminants::Bn254Double]; + total_chips += 1; + + let bls12381_add_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_ADD).unwrap_or(&0); + total_area += (bls12381_add_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Add]; + total_chips += 1; + + let bls12381_double_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_DOUBLE).unwrap_or(&0); + total_area += + (bls12381_double_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Double]; + total_chips += 1; + + let uint256_mul_events = *self.syscall_counts.get(&SyscallCode::UINT256_MUL).unwrap_or(&0); + total_area += (uint256_mul_events as u64) * costs[&RiscvAirDiscriminants::Uint256Mul]; + total_chips += 1; + + let bls12381_fp_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_FP_ADD).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BLS12381_FP_SUB).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BLS12381_FP_MUL).unwrap_or(&0); + total_area += (bls12381_fp_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Fp]; + total_chips += 1; + + let bls12381_fp2_addsub_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_FP2_ADD).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BLS12381_FP2_SUB).unwrap_or(&0); + total_area += + (bls12381_fp2_addsub_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Fp2AddSub]; + total_chips += 1; + + let bls12381_fp2_mul_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_FP2_MUL).unwrap_or(&0); + total_area += + (bls12381_fp2_mul_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Fp2Mul]; + total_chips += 1; + + let bn254_fp_events = *self.syscall_counts.get(&SyscallCode::BN254_FP_ADD).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BN254_FP_SUB).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BN254_FP_MUL).unwrap_or(&0); + total_area += (bn254_fp_events as u64) * costs[&RiscvAirDiscriminants::Bn254Fp]; + total_chips += 1; + + let bn254_fp2_addsub_events = + *self.syscall_counts.get(&SyscallCode::BN254_FP2_ADD).unwrap_or(&0) + + *self.syscall_counts.get(&SyscallCode::BN254_FP2_SUB).unwrap_or(&0); + total_area += + (bn254_fp2_addsub_events as u64) * costs[&RiscvAirDiscriminants::Bn254Fp2AddSub]; + total_chips += 1; + + let bn254_fp2_mul_events = + *self.syscall_counts.get(&SyscallCode::BN254_FP2_MUL).unwrap_or(&0); + total_area += (bn254_fp2_mul_events as u64) * costs[&RiscvAirDiscriminants::Bn254Fp2Mul]; + total_chips += 1; + + let bls12381_decompress_events = + *self.syscall_counts.get(&SyscallCode::BLS12381_DECOMPRESS).unwrap_or(&0); + total_area += + (bls12381_decompress_events as u64) * costs[&RiscvAirDiscriminants::Bls12381Decompress]; + total_chips += 1; + + let divrem_events = *self.opcode_counts.get(&Opcode::DIV).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::REM).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::DIVU).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::REMU).unwrap_or(&0); + total_area += (divrem_events as u64) * costs[&RiscvAirDiscriminants::DivRem]; + total_chips += 1; + + let addsub_events = *self.opcode_counts.get(&Opcode::ADD).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::SUB).unwrap_or(&0); + total_area += (addsub_events as u64) * costs[&RiscvAirDiscriminants::Add]; + total_chips += 1; + + let bitwise_events = *self.opcode_counts.get(&Opcode::AND).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::OR).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::XOR).unwrap_or(&0); + total_area += (bitwise_events as u64) * costs[&RiscvAirDiscriminants::Bitwise]; + total_chips += 1; + + let mul_events = *self.opcode_counts.get(&Opcode::MUL).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::MULH).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::MULHU).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::MULHSU).unwrap_or(&0); + total_area += (mul_events as u64) * costs[&RiscvAirDiscriminants::Mul]; + total_chips += 1; + + let shift_right_events = *self.opcode_counts.get(&Opcode::SRL).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::SRA).unwrap_or(&0); + total_area += (shift_right_events as u64) * costs[&RiscvAirDiscriminants::ShiftRight]; + total_chips += 1; + + let shift_left_events = *self.opcode_counts.get(&Opcode::SLL).unwrap_or(&0); + total_area += (shift_left_events as u64) * costs[&RiscvAirDiscriminants::ShiftLeft]; + total_chips += 1; + + let lt_events = *self.opcode_counts.get(&Opcode::SLT).unwrap_or(&0) + + *self.opcode_counts.get(&Opcode::SLTU).unwrap_or(&0); + total_area += (lt_events as u64) * costs[&RiscvAirDiscriminants::Lt]; + total_chips += 1; + + let memory_initialize_events = self.touched_memory_addresses; + total_area += (memory_initialize_events as u64) * costs[&RiscvAirDiscriminants::MemoryInit]; + total_chips += 1; + + let memory_finalize_events = self.touched_memory_addresses; + total_area += (memory_finalize_events as u64) * costs[&RiscvAirDiscriminants::MemoryFinal]; + total_chips += 1; + + assert_eq!(total_chips, chips.len(), "chip count mismatch"); + total_area + } +} diff --git a/crates/core/machine/src/riscv/mod.rs b/crates/core/machine/src/riscv/mod.rs new file mode 100644 index 0000000000..7fba0e1ec2 --- /dev/null +++ b/crates/core/machine/src/riscv/mod.rs @@ -0,0 +1,547 @@ +pub mod cost; + +use crate::{ + memory::{MemoryChipType, MemoryProgramChip}, + syscall::precompiles::fptower::{Fp2AddSubAssignChip, Fp2MulAssignChip, FpOpChip}, +}; +use hashbrown::HashMap; +use p3_field::PrimeField32; +pub use riscv_chips::*; +use sp1_curves::weierstrass::{bls12_381::Bls12381BaseField, bn254::Bn254BaseField}; +use sp1_stark::{ + air::{MachineAir, SP1_PROOF_NUM_PV_ELTS}, + Chip, StarkGenericConfig, StarkMachine, +}; +use strum_macros::{EnumDiscriminants, EnumIter}; +use tracing::instrument; + +/// A module for importing all the different RISC-V chips. +pub(crate) mod riscv_chips { + pub use crate::{ + alu::{AddSubChip, BitwiseChip, DivRemChip, LtChip, MulChip, ShiftLeft, ShiftRightChip}, + bytes::ByteChip, + cpu::CpuChip, + memory::MemoryChip, + program::ProgramChip, + syscall::precompiles::{ + edwards::{EdAddAssignChip, EdDecompressChip}, + keccak256::KeccakPermuteChip, + sha256::{ShaCompressChip, ShaExtendChip}, + uint256::Uint256MulChip, + weierstrass::{ + WeierstrassAddAssignChip, WeierstrassDecompressChip, WeierstrassDoubleAssignChip, + }, + }, + }; + pub use sp1_curves::{ + edwards::{ed25519::Ed25519Parameters, EdwardsCurve}, + weierstrass::{ + bls12_381::Bls12381Parameters, bn254::Bn254Parameters, secp256k1::Secp256k1Parameters, + SwCurve, + }, + }; +} + +/// An AIR for encoding RISC-V execution. +/// +/// This enum contains all the different AIRs that are used in the Sp1 RISC-V IOP. Each variant is +/// a different AIR that is used to encode a different part of the RISC-V execution, and the +/// different AIR variants have a joint lookup argument. +#[derive(sp1_derive::MachineAir, EnumDiscriminants)] +#[strum_discriminants(derive(Hash, EnumIter))] +pub enum RiscvAir { + /// An AIR that containts a preprocessed program table and a lookup for the instructions. + Program(ProgramChip), + /// An AIR for the RISC-V CPU. Each row represents a cpu cycle. + Cpu(CpuChip), + /// An AIR for the RISC-V Add and SUB instruction. + Add(AddSubChip), + /// An AIR for RISC-V Bitwise instructions. + Bitwise(BitwiseChip), + /// An AIR for RISC-V Mul instruction. + Mul(MulChip), + /// An AIR for RISC-V Div and Rem instructions. + DivRem(DivRemChip), + /// An AIR for RISC-V Lt instruction. + Lt(LtChip), + /// An AIR for RISC-V SLL instruction. + ShiftLeft(ShiftLeft), + /// An AIR for RISC-V SRL and SRA instruction. + ShiftRight(ShiftRightChip), + /// A lookup table for byte operations. + ByteLookup(ByteChip), + /// A table for initializing the memory state. + MemoryInit(MemoryChip), + /// A table for finalizing the memory state. + MemoryFinal(MemoryChip), + /// A table for initializing the program memory. + ProgramMemory(MemoryProgramChip), + /// A precompile for sha256 extend. + Sha256Extend(ShaExtendChip), + /// A precompile for sha256 compress. + Sha256Compress(ShaCompressChip), + /// A precompile for addition on the Elliptic curve ed25519. + Ed25519Add(EdAddAssignChip>), + /// A precompile for decompressing a point on the Edwards curve ed25519. + Ed25519Decompress(EdDecompressChip), + /// A precompile for decompressing a point on the K256 curve. + K256Decompress(WeierstrassDecompressChip>), + /// A precompile for addition on the Elliptic curve secp256k1. + Secp256k1Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve secp256k1. + Secp256k1Double(WeierstrassDoubleAssignChip>), + /// A precompile for the Keccak permutation. + KeccakP(KeccakPermuteChip), + /// A precompile for addition on the Elliptic curve bn254. + Bn254Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve bn254. + Bn254Double(WeierstrassDoubleAssignChip>), + /// A precompile for addition on the Elliptic curve bls12_381. + Bls12381Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve bls12_381. + Bls12381Double(WeierstrassDoubleAssignChip>), + /// A precompile for uint256 mul. + Uint256Mul(Uint256MulChip), + /// A precompile for decompressing a point on the BLS12-381 curve. + Bls12381Decompress(WeierstrassDecompressChip>), + /// A precompile for BLS12-381 fp operation. + Bls12381Fp(FpOpChip), + /// A precompile for BLS12-381 fp2 multiplication. + Bls12381Fp2Mul(Fp2MulAssignChip), + /// A precompile for BLS12-381 fp2 addition/subtraction. + Bls12381Fp2AddSub(Fp2AddSubAssignChip), + /// A precompile for BN-254 fp operation. + Bn254Fp(FpOpChip), + /// A precompile for BN-254 fp2 multiplication. + Bn254Fp2Mul(Fp2MulAssignChip), + /// A precompile for BN-254 fp2 addition/subtraction. + Bn254Fp2AddSub(Fp2AddSubAssignChip), +} + +impl RiscvAir { + #[instrument("construct RiscvAir machine", level = "debug", skip_all)] + pub fn machine>(config: SC) -> StarkMachine { + let chips = Self::chips(); + StarkMachine::new(config, chips, SP1_PROOF_NUM_PV_ELTS) + } + + /// Get all the different RISC-V AIRs. + pub fn chips() -> Vec> { + let (chips, _) = Self::get_chips_and_costs(); + chips + } + + /// Get all the costs of the different RISC-V AIRs. + pub fn costs() -> HashMap { + let (_, costs) = Self::get_chips_and_costs(); + costs + } + + /// Get all the different RISC-V AIRs. + pub fn get_chips_and_costs() -> (Vec>, HashMap) { + let mut costs: HashMap = HashMap::new(); + + // The order of the chips is used to determine the order of trace generation. + let mut chips = vec![]; + let cpu = Chip::new(RiscvAir::Cpu(CpuChip::default())); + costs.insert(RiscvAirDiscriminants::Cpu, cpu.cost()); + chips.push(cpu); + + let program = Chip::new(RiscvAir::Program(ProgramChip::default())); + chips.push(program); + + let sha_extend = Chip::new(RiscvAir::Sha256Extend(ShaExtendChip::default())); + costs.insert(RiscvAirDiscriminants::Sha256Extend, 48 * sha_extend.cost()); + chips.push(sha_extend); + + let sha_compress = Chip::new(RiscvAir::Sha256Compress(ShaCompressChip::default())); + costs.insert(RiscvAirDiscriminants::Sha256Compress, 80 * sha_compress.cost()); + chips.push(sha_compress); + + let ed_add_assign = Chip::new(RiscvAir::Ed25519Add(EdAddAssignChip::< + EdwardsCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Ed25519Add, ed_add_assign.cost()); + chips.push(ed_add_assign); + + let ed_decompress = Chip::new(RiscvAir::Ed25519Decompress(EdDecompressChip::< + Ed25519Parameters, + >::default())); + costs.insert(RiscvAirDiscriminants::Ed25519Decompress, ed_decompress.cost()); + chips.push(ed_decompress); + + let k256_decompress = Chip::new(RiscvAir::K256Decompress(WeierstrassDecompressChip::< + SwCurve, + >::with_lsb_rule())); + costs.insert(RiscvAirDiscriminants::K256Decompress, k256_decompress.cost()); + chips.push(k256_decompress); + + let secp256k1_add_assign = Chip::new(RiscvAir::Secp256k1Add(WeierstrassAddAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Secp256k1Add, secp256k1_add_assign.cost()); + chips.push(secp256k1_add_assign); + + let secp256k1_double_assign = + Chip::new(RiscvAir::Secp256k1Double(WeierstrassDoubleAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Secp256k1Double, secp256k1_double_assign.cost()); + chips.push(secp256k1_double_assign); + + let keccak_permute = Chip::new(RiscvAir::KeccakP(KeccakPermuteChip::new())); + costs.insert(RiscvAirDiscriminants::KeccakP, 24 * keccak_permute.cost()); + chips.push(keccak_permute); + + let bn254_add_assign = Chip::new(RiscvAir::Bn254Add(WeierstrassAddAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Bn254Add, bn254_add_assign.cost()); + chips.push(bn254_add_assign); + + let bn254_double_assign = Chip::new(RiscvAir::Bn254Double(WeierstrassDoubleAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Bn254Double, bn254_double_assign.cost()); + chips.push(bn254_double_assign); + + let bls12381_add = Chip::new(RiscvAir::Bls12381Add(WeierstrassAddAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Bls12381Add, bls12381_add.cost()); + chips.push(bls12381_add); + + let bls12381_double = Chip::new(RiscvAir::Bls12381Double(WeierstrassDoubleAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Bls12381Double, bls12381_double.cost()); + chips.push(bls12381_double); + + let uint256_mul = Chip::new(RiscvAir::Uint256Mul(Uint256MulChip::default())); + costs.insert(RiscvAirDiscriminants::Uint256Mul, uint256_mul.cost()); + chips.push(uint256_mul); + + let bls12381_fp = Chip::new(RiscvAir::Bls12381Fp(FpOpChip::::new())); + costs.insert(RiscvAirDiscriminants::Bls12381Fp, bls12381_fp.cost()); + chips.push(bls12381_fp); + + let bls12381_fp2_addsub = + Chip::new(RiscvAir::Bls12381Fp2AddSub(Fp2AddSubAssignChip::::new())); + costs.insert(RiscvAirDiscriminants::Bls12381Fp2AddSub, bls12381_fp2_addsub.cost()); + chips.push(bls12381_fp2_addsub); + + let bls12381_fp2_mul = + Chip::new(RiscvAir::Bls12381Fp2Mul(Fp2MulAssignChip::::new())); + costs.insert(RiscvAirDiscriminants::Bls12381Fp2Mul, bls12381_fp2_mul.cost()); + chips.push(bls12381_fp2_mul); + + let bn254_fp = Chip::new(RiscvAir::Bn254Fp(FpOpChip::::new())); + costs.insert(RiscvAirDiscriminants::Bn254Fp, bn254_fp.cost()); + chips.push(bn254_fp); + + let bn254_fp2_addsub = + Chip::new(RiscvAir::Bn254Fp2AddSub(Fp2AddSubAssignChip::::new())); + costs.insert(RiscvAirDiscriminants::Bn254Fp2AddSub, bn254_fp2_addsub.cost()); + chips.push(bn254_fp2_addsub); + + let bn254_fp2_mul = + Chip::new(RiscvAir::Bn254Fp2Mul(Fp2MulAssignChip::::new())); + costs.insert(RiscvAirDiscriminants::Bn254Fp2Mul, bn254_fp2_mul.cost()); + chips.push(bn254_fp2_mul); + + let bls12381_decompress = + Chip::new(RiscvAir::Bls12381Decompress(WeierstrassDecompressChip::< + SwCurve, + >::with_lexicographic_rule())); + costs.insert(RiscvAirDiscriminants::Bls12381Decompress, bls12381_decompress.cost()); + chips.push(bls12381_decompress); + + let div_rem = Chip::new(RiscvAir::DivRem(DivRemChip::default())); + costs.insert(RiscvAirDiscriminants::DivRem, div_rem.cost()); + chips.push(div_rem); + + let add_sub = Chip::new(RiscvAir::Add(AddSubChip::default())); + costs.insert(RiscvAirDiscriminants::Add, add_sub.cost()); + chips.push(add_sub); + + let bitwise = Chip::new(RiscvAir::Bitwise(BitwiseChip::default())); + costs.insert(RiscvAirDiscriminants::Bitwise, bitwise.cost()); + chips.push(bitwise); + + let mul = Chip::new(RiscvAir::Mul(MulChip::default())); + costs.insert(RiscvAirDiscriminants::Mul, mul.cost()); + chips.push(mul); + + let shift_right = Chip::new(RiscvAir::ShiftRight(ShiftRightChip::default())); + costs.insert(RiscvAirDiscriminants::ShiftRight, shift_right.cost()); + chips.push(shift_right); + + let shift_left = Chip::new(RiscvAir::ShiftLeft(ShiftLeft::default())); + costs.insert(RiscvAirDiscriminants::ShiftLeft, shift_left.cost()); + chips.push(shift_left); + + let lt = Chip::new(RiscvAir::Lt(LtChip::default())); + costs.insert(RiscvAirDiscriminants::Lt, lt.cost()); + chips.push(lt); + + let memory_init = + Chip::new(RiscvAir::MemoryInit(MemoryChip::new(MemoryChipType::Initialize))); + costs.insert(RiscvAirDiscriminants::MemoryInit, memory_init.cost()); + chips.push(memory_init); + + let memory_finalize = + Chip::new(RiscvAir::MemoryFinal(MemoryChip::new(MemoryChipType::Finalize))); + costs.insert(RiscvAirDiscriminants::MemoryFinal, memory_finalize.cost()); + chips.push(memory_finalize); + + let memory_program = Chip::new(RiscvAir::ProgramMemory(MemoryProgramChip::default())); + costs.insert(RiscvAirDiscriminants::ProgramMemory, memory_program.cost()); + chips.push(memory_program); + + let byte = Chip::new(RiscvAir::ByteLookup(ByteChip::default())); + costs.insert(RiscvAirDiscriminants::ByteLookup, byte.cost()); + chips.push(byte); + + (chips, costs) + } +} + +impl PartialEq for RiscvAir { + fn eq(&self, other: &Self) -> bool { + self.name() == other.name() + } +} + +impl Eq for RiscvAir {} + +impl core::hash::Hash for RiscvAir { + fn hash(&self, state: &mut H) { + self.name().hash(state); + } +} + +#[cfg(test)] +#[allow(non_snake_case)] +pub mod tests { + + use crate::{ + io::SP1Stdin, + riscv::RiscvAir, + utils, + utils::{prove, run_test, setup_logger}, + }; + + use sp1_core_executor::{ + programs::tests::{ + fibonacci_program, simple_memory_program, simple_program, ssz_withdrawals_program, + }, + Instruction, Opcode, Program, + }; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, SP1CoreOpts, StarkProvingKey, + StarkVerifyingKey, + }; + + #[test] + fn test_simple_prove() { + utils::setup_logger(); + let program = simple_program(); + run_test::>(program).unwrap(); + } + + #[test] + fn test_shift_prove() { + utils::setup_logger(); + let shift_ops = [Opcode::SRL, Opcode::SRA, Opcode::SLL]; + let operands = + [(1, 1), (1234, 5678), (0xffff, 0xffff - 1), (u32::MAX - 1, u32::MAX), (u32::MAX, 0)]; + for shift_op in shift_ops.iter() { + for op in operands.iter() { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, op.0, false, true), + Instruction::new(Opcode::ADD, 30, 0, op.1, false, true), + Instruction::new(*shift_op, 31, 29, 3, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + } + } + + #[test] + fn test_sub_prove() { + utils::setup_logger(); + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 30, 0, 8, false, true), + Instruction::new(Opcode::SUB, 31, 30, 29, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + + #[test] + fn test_add_prove() { + setup_logger(); + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 30, 0, 8, false, true), + Instruction::new(Opcode::ADD, 31, 30, 29, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + + #[test] + fn test_mul_prove() { + let mul_ops = [Opcode::MUL, Opcode::MULH, Opcode::MULHU, Opcode::MULHSU]; + utils::setup_logger(); + let operands = + [(1, 1), (1234, 5678), (8765, 4321), (0xffff, 0xffff - 1), (u32::MAX - 1, u32::MAX)]; + for mul_op in mul_ops.iter() { + for operand in operands.iter() { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, operand.0, false, true), + Instruction::new(Opcode::ADD, 30, 0, operand.1, false, true), + Instruction::new(*mul_op, 31, 30, 29, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + } + } + + #[test] + fn test_lt_prove() { + setup_logger(); + let less_than = [Opcode::SLT, Opcode::SLTU]; + for lt_op in less_than.iter() { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 30, 0, 8, false, true), + Instruction::new(*lt_op, 31, 30, 29, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + } + + #[test] + fn test_bitwise_prove() { + setup_logger(); + let bitwise_opcodes = [Opcode::XOR, Opcode::OR, Opcode::AND]; + + for bitwise_op in bitwise_opcodes.iter() { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 30, 0, 8, false, true), + Instruction::new(*bitwise_op, 31, 30, 29, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + } + + #[test] + fn test_divrem_prove() { + setup_logger(); + let div_rem_ops = [Opcode::DIV, Opcode::DIVU, Opcode::REM, Opcode::REMU]; + let operands = [ + (1, 1), + (123, 456 * 789), + (123 * 456, 789), + (0xffff * (0xffff - 1), 0xffff), + (u32::MAX - 5, u32::MAX - 7), + ]; + for div_rem_op in div_rem_ops.iter() { + for op in operands.iter() { + let instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, op.0, false, true), + Instruction::new(Opcode::ADD, 30, 0, op.1, false, true), + Instruction::new(*div_rem_op, 31, 29, 30, false, false), + ]; + let program = Program::new(instructions, 0, 0); + run_test::>(program).unwrap(); + } + } + } + + #[test] + fn test_fibonacci_prove_simple() { + setup_logger(); + let program = fibonacci_program(); + run_test::>(program).unwrap(); + } + + #[test] + fn test_fibonacci_prove_checkpoints() { + setup_logger(); + + let program = fibonacci_program(); + let stdin = SP1Stdin::new(); + let mut opts = SP1CoreOpts::default(); + opts.shard_size = 1024; + opts.shard_batch_size = 2; + prove::<_, CpuProver<_, _>>(program, &stdin, BabyBearPoseidon2::new(), opts).unwrap(); + } + + #[test] + fn test_fibonacci_prove_batch() { + setup_logger(); + let program = fibonacci_program(); + let stdin = SP1Stdin::new(); + prove::<_, CpuProver<_, _>>( + program, + &stdin, + BabyBearPoseidon2::new(), + SP1CoreOpts::default(), + ) + .unwrap(); + } + + #[test] + fn test_simple_memory_program_prove() { + setup_logger(); + let program = simple_memory_program(); + run_test::>(program).unwrap(); + } + + #[test] + fn test_ssz_withdrawal() { + setup_logger(); + let program = ssz_withdrawals_program(); + run_test::>(program).unwrap(); + } + + #[test] + fn test_key_serde() { + let program = ssz_withdrawals_program(); + let config = BabyBearPoseidon2::new(); + let machine = RiscvAir::machine(config); + let (pk, vk) = machine.setup(&program); + + let serialized_pk = bincode::serialize(&pk).unwrap(); + let deserialized_pk: StarkProvingKey = + bincode::deserialize(&serialized_pk).unwrap(); + assert_eq!(pk.commit, deserialized_pk.commit); + assert_eq!(pk.pc_start, deserialized_pk.pc_start); + assert_eq!(pk.traces, deserialized_pk.traces); + assert_eq!(pk.data.root(), deserialized_pk.data.root()); + assert_eq!(pk.chip_ordering, deserialized_pk.chip_ordering); + + let serialized_vk = bincode::serialize(&vk).unwrap(); + let deserialized_vk: StarkVerifyingKey = + bincode::deserialize(&serialized_vk).unwrap(); + assert_eq!(vk.commit, deserialized_vk.commit); + assert_eq!(vk.pc_start, deserialized_vk.pc_start); + assert_eq!(vk.chip_information.len(), deserialized_vk.chip_information.len()); + for (a, b) in vk.chip_information.iter().zip(deserialized_vk.chip_information.iter()) { + assert_eq!(a.0, b.0); + assert_eq!(a.1.log_n, b.1.log_n); + assert_eq!(a.1.shift, b.1.shift); + assert_eq!(a.2.height, b.2.height); + assert_eq!(a.2.width, b.2.width); + } + assert_eq!(vk.chip_ordering, deserialized_vk.chip_ordering); + } +} diff --git a/core/src/runtime/syscall.rs b/crates/core/machine/src/runtime/syscall.rs similarity index 71% rename from core/src/runtime/syscall.rs rename to crates/core/machine/src/runtime/syscall.rs index 7a6465ee30..bb88f32257 100644 --- a/core/src/runtime/syscall.rs +++ b/crates/core/machine/src/runtime/syscall.rs @@ -5,9 +5,11 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; +use crate::operations::field::field_op::FieldOperation; use crate::runtime::{Register, Runtime}; use crate::syscall::precompiles::edwards::EdAddAssignChip; use crate::syscall::precompiles::edwards::EdDecompressChip; +use crate::syscall::precompiles::fptower::{Fp2AddSubSyscall, Fp2MulAssignChip, FpOpSyscall}; use crate::syscall::precompiles::keccak256::KeccakPermuteChip; use crate::syscall::precompiles::sha256::{ShaCompressChip, ShaExtendChip}; use crate::syscall::precompiles::uint256::Uint256MulChip; @@ -19,7 +21,8 @@ use crate::syscall::{ SyscallHalt, SyscallHintLen, SyscallHintRead, SyscallVerifySP1Proof, SyscallWrite, }; use crate::utils::ec::edwards::ed25519::{Ed25519, Ed25519Parameters}; -use crate::utils::ec::weierstrass::bls12_381::Bls12381; +use crate::utils::ec::weierstrass::bls12_381::{Bls12381, Bls12381BaseField}; +use crate::utils::ec::weierstrass::bn254::Bn254BaseField; use crate::utils::ec::weierstrass::{bn254::Bn254, secp256k1::Secp256k1}; use crate::{runtime::ExecutionRecord, runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; @@ -102,6 +105,42 @@ pub enum SyscallCode { /// Executes the `BLS12381_DOUBLE` precompile. BLS12381_DOUBLE = 0x00_00_01_1F, + + /// Executes the `BLS12381_FP_ADD` precompile. + BLS12381_FP_ADD = 0x00_01_01_20, + + /// Executes the `BLS12381_FP_SUB` precompile. + BLS12381_FP_SUB = 0x00_01_01_21, + + /// Executes the `BLS12381_FP_MUL` precompile. + BLS12381_FP_MUL = 0x00_01_01_22, + + /// Executes the `BLS12381_FP2_ADD` precompile. + BLS12381_FP2_ADD = 0x00_01_01_23, + + /// Executes the `BLS12381_FP2_SUB` precompile. + BLS12381_FP2_SUB = 0x00_01_01_24, + + /// Executes the `BLS12381_FP2_MUL` precompile. + BLS12381_FP2_MUL = 0x00_01_01_25, + + /// Executes the `BN254_FP_ADD` precompile. + BN254_FP_ADD = 0x00_01_01_26, + + /// Executes the `BN254_FP_SUB` precompile. + BN254_FP_SUB = 0x00_01_01_27, + + /// Executes the `BN254_FP_MUL` precompile. + BN254_FP_MUL = 0x00_01_01_28, + + /// Executes the `BN254_FP2_ADD` precompile. + BN254_FP2_ADD = 0x00_01_01_29, + + /// Executes the `BN254_FP2_SUB` precompile. + BN254_FP2_SUB = 0x00_01_01_2A, + + /// Executes the `BN254_FP2_MUL` precompile. + BN254_FP2_MUL = 0x00_01_01_2B, } impl SyscallCode { @@ -130,6 +169,18 @@ impl SyscallCode { 0x00_00_00_F0 => SyscallCode::HINT_LEN, 0x00_00_00_F1 => SyscallCode::HINT_READ, 0x00_01_01_1D => SyscallCode::UINT256_MUL, + 0x00_01_01_20 => SyscallCode::BLS12381_FP_ADD, + 0x00_01_01_21 => SyscallCode::BLS12381_FP_SUB, + 0x00_01_01_22 => SyscallCode::BLS12381_FP_MUL, + 0x00_01_01_23 => SyscallCode::BLS12381_FP2_ADD, + 0x00_01_01_24 => SyscallCode::BLS12381_FP2_SUB, + 0x00_01_01_25 => SyscallCode::BLS12381_FP2_MUL, + 0x00_01_01_26 => SyscallCode::BN254_FP_ADD, + 0x00_01_01_27 => SyscallCode::BN254_FP_SUB, + 0x00_01_01_28 => SyscallCode::BN254_FP_MUL, + 0x00_01_01_29 => SyscallCode::BN254_FP2_ADD, + 0x00_01_01_2A => SyscallCode::BN254_FP2_SUB, + 0x00_01_01_2B => SyscallCode::BN254_FP2_MUL, 0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS, _ => panic!("invalid syscall number: {}", value), } @@ -146,6 +197,19 @@ impl SyscallCode { pub fn num_cycles(&self) -> u32 { (*self as u32).to_le_bytes()[2].into() } + + /// Map a syscall to another one in order to coalesce their counts. + pub fn count_map(&self) -> Self { + match self { + SyscallCode::BN254_FP_SUB => SyscallCode::BN254_FP_ADD, + SyscallCode::BN254_FP_MUL => SyscallCode::BN254_FP_ADD, + SyscallCode::BN254_FP2_SUB => SyscallCode::BN254_FP2_ADD, + SyscallCode::BLS12381_FP_SUB => SyscallCode::BLS12381_FP_ADD, + SyscallCode::BLS12381_FP_MUL => SyscallCode::BLS12381_FP_ADD, + SyscallCode::BLS12381_FP2_SUB => SyscallCode::BLS12381_FP2_ADD, + _ => *self, + } + } } impl fmt::Display for SyscallCode { @@ -238,19 +302,19 @@ impl<'a, 'b> SyscallContext<'a, 'b> { /// Get the current value of a register, but doesn't use a memory record. /// This is generally unconstrained, so you must be careful using it. - pub fn register_unsafe(&self, register: Register) -> u32 { + pub fn register_unsafe(&mut self, register: Register) -> u32 { self.rt.register(register) } - pub fn byte_unsafe(&self, addr: u32) -> u8 { + pub fn byte_unsafe(&mut self, addr: u32) -> u8 { self.rt.byte(addr) } - pub fn word_unsafe(&self, addr: u32) -> u32 { + pub fn word_unsafe(&mut self, addr: u32) -> u32 { self.rt.word(addr) } - pub fn slice_unsafe(&self, addr: u32, len: usize) -> Vec { + pub fn slice_unsafe(&mut self, addr: u32, len: usize) -> Vec { let mut values = Vec::new(); for i in 0..len { values.push(self.rt.word(addr + i as u32 * 4)); @@ -313,6 +377,58 @@ pub fn default_syscall_map() -> HashMap> { Arc::new(WeierstrassDoubleAssignChip::::new()), ); syscall_map.insert(SyscallCode::UINT256_MUL, Arc::new(Uint256MulChip::new())); + syscall_map.insert( + SyscallCode::BLS12381_FP_ADD, + Arc::new(FpOpSyscall::::new(FieldOperation::Add)), + ); + syscall_map.insert( + SyscallCode::BLS12381_FP_SUB, + Arc::new(FpOpSyscall::::new(FieldOperation::Sub)), + ); + syscall_map.insert( + SyscallCode::BLS12381_FP_MUL, + Arc::new(FpOpSyscall::::new(FieldOperation::Mul)), + ); + syscall_map.insert( + SyscallCode::BLS12381_FP2_ADD, + Arc::new(Fp2AddSubSyscall::::new( + FieldOperation::Add, + )), + ); + syscall_map.insert( + SyscallCode::BLS12381_FP2_SUB, + Arc::new(Fp2AddSubSyscall::::new( + FieldOperation::Sub, + )), + ); + syscall_map.insert( + SyscallCode::BLS12381_FP2_MUL, + Arc::new(Fp2MulAssignChip::::new()), + ); + syscall_map.insert( + SyscallCode::BN254_FP_ADD, + Arc::new(FpOpSyscall::::new(FieldOperation::Add)), + ); + syscall_map.insert( + SyscallCode::BN254_FP_SUB, + Arc::new(FpOpSyscall::::new(FieldOperation::Sub)), + ); + syscall_map.insert( + SyscallCode::BN254_FP_MUL, + Arc::new(FpOpSyscall::::new(FieldOperation::Mul)), + ); + syscall_map.insert( + SyscallCode::BN254_FP2_ADD, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Add)), + ); + syscall_map.insert( + SyscallCode::BN254_FP2_SUB, + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Sub)), + ); + syscall_map.insert( + SyscallCode::BN254_FP2_MUL, + Arc::new(Fp2MulAssignChip::::new()), + ); syscall_map.insert( SyscallCode::ENTER_UNCONSTRAINED, Arc::new(SyscallEnterUnconstrained::new()), @@ -428,6 +544,42 @@ mod tests { SyscallCode::BLS12381_DECOMPRESS => { assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_DECOMPRESS) } + SyscallCode::BLS12381_FP_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP_ADD) + } + SyscallCode::BLS12381_FP_SUB => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP_SUB) + } + SyscallCode::BLS12381_FP_MUL => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP_MUL) + } + SyscallCode::BLS12381_FP2_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP2_ADD) + } + SyscallCode::BLS12381_FP2_SUB => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP2_SUB) + } + SyscallCode::BLS12381_FP2_MUL => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_FP2_MUL) + } + SyscallCode::BN254_FP_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP_ADD) + } + SyscallCode::BN254_FP_SUB => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP_SUB) + } + SyscallCode::BN254_FP_MUL => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP_MUL) + } + SyscallCode::BN254_FP2_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP2_ADD) + } + SyscallCode::BN254_FP2_SUB => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP2_SUB) + } + SyscallCode::BN254_FP2_MUL => { + assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_FP2_MUL) + } } } } diff --git a/core/src/runtime/utils.rs b/crates/core/machine/src/runtime/utils.rs similarity index 70% rename from core/src/runtime/utils.rs rename to crates/core/machine/src/runtime/utils.rs index 41e132bccc..7c0ad541e7 100644 --- a/core/src/runtime/utils.rs +++ b/crates/core/machine/src/runtime/utils.rs @@ -1,7 +1,6 @@ use std::io::Write; use super::{Instruction, Runtime}; -use crate::runtime::Register; pub const fn align(addr: u32) -> u32 { addr - addr % 4 @@ -42,30 +41,31 @@ impl<'a> Runtime<'a> { // If RUST_LOG is set to "trace", then log the current state of the runtime every cycle. let width = 12; + let registers = self.registers(); log::trace!( "clk={} [pc=0x{:x?}] {: Self { + Self + } +} +``` + +### Define the Chip's Data Structure +Define the necessary data structures that your chip will use. This might include columns for memory operations, input values, and output results. For instance, in the Uint256MulChip, we define the columns as follows: + +```rust +#[derive(Debug, Clone, AlignedBorrow)] +#[repr(C)] +pub struct CustomOpCols { + pub shard: T, + pub channel: T, + pub clk: T, + pub x_ptr: T, + pub y_ptr: T, + pub x_memory: GenericArray, WordsFieldElement>, + pub y_memory: GenericArray, WordsFieldElement>, + pub output: FieldOpCols, +} +``` +Adjust these fields according to your chip. + +### Implement the Chip Logic +The Syscall trait is where the core execution logic of your chip will reside. This involves defining how the chip interacts with the SP1 runtime during execution time. + +```rust +impl Syscall for Uint256MulChip { + fn num_extra_cycles(&self) -> u32 { + 1 + } + + fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { + // Your execution logic here + // Parse input pointers, perform the multiplication, and write the result + } +} +``` + +### Implement the `MachineAir` Trait +The `MachineAir` trait integrates your chip with SP1’s Algebraic Intermediate Representation (AIR). This involves generating and evaluating traces that represent the chip's operations. + +```rust +impl MachineAir for CustomOpChip { + type Record = ExecutionRecord; + type Program = Program; + + fn name(&self) -> String { + "CustomOp".to_string() + } + + fn generate_trace( + &self, + input: &ExecutionRecord, + output: &mut ExecutionRecord, + ) -> RowMajorMatrix { + // Implement trace generation logic + } + + fn included(&self, shard: &Self::Record) -> bool { + // Implement logic to determine if this chip should be included + !shard.custom_op_events.is_empty() + } +} +``` +You will also have to update `core/src/runtime/record.rs` accordingly to handle these new events. +#### Add a new field for your chip's events +In the `ExecutionRecord` struct, add a new field to track events specific to your chip. This field will store all events generated by your chip during execution. + +```rust +#[derive(Default, Clone, Debug, Serialize, Deserialize)] +pub struct ExecutionRecord { + // Other existing fields... + + /// A trace of the events for your custom operation. + pub custom_op_events: Vec, +} +``` + +#### Update the `stats` method +In the `stats` method, add an entry to track the number of events associated with your chip. + +```rust +fn stats(&self) -> HashMap { + let mut stats = HashMap::new(); + // Other existing entries... + + stats.insert("custom_op_events".to_string(), self.custom_op_events.len()); + // Add other stats as necessary + stats +} +``` +#### Update the `append` method +In the append method, ensure that events from your chip are correctly appended when merging two `ExecutionRecord` instances. + +```rust +fn append(&mut self, other: &mut ExecutionRecord) { + // Other existing append operations... + + self.custom_op_events.append(&mut other.custom_op_events); +} +``` + +#### Update the `defer` method +Modify the `defer` method to handle the deferring of events specific to your chip. + +```rust +pub fn defer(&mut self) -> ExecutionRecord { + ExecutionRecord { + // Other deferred events... + + custom_op_events: std::mem::take(&mut self.custom_op_events), + ..Default::default() + } +} +``` + +#### Update the `split` method +In the `split` method, ensure that events associated with your chip are properly split when distributing deferred events across shards. + +```rust +pub fn split(&mut self, last: bool, opts: SplitOpts) -> Vec { + let mut shards = Vec::new(); + + split_events!( + self, + custom_op_events, + shards, + opts.deferred_shift_threshold, + last + ); + + // Other event splits... + + shards +} +``` + +### Implement the `Air` and `BaseAir` traits +To fully integrate your chip with the SP1 AIR framework, implement the `Air` and `BaseAir` traits. These traits define how your chip’s operations are evaluated within the AIR system. + +```rust +impl BaseAir for CustomOpChip { + fn width(&self) -> usize { + // Define the number of columns your chip requires + NUM_COLS + } +} + +impl Air for CustomOpChip +where + AB: SP1AirBuilder, + Limbs::Limbs>: Copy, +{ + fn eval(&self, builder: &mut AB) { + // Implement the evaluation logic for your chip + } +} +``` +> **Important Note**: Make sure that the `eval` method properly accounts for all aspects of your chip’s behavior, as discrepancies between `eval` and the actual execution logic can lead to proof failures or incorrect verification results even when `execute` is correct. + +## Register a New Syscall +### Add a New Enum Variant +In the `SyscallCode` enum, define a new variant for your custom syscall. The variant should be given a unique value. + +```rust +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter, Ord, PartialOrd, Serialize, Deserialize)] +#[allow(non_camel_case_types)] +pub enum SyscallCode { + // Existing syscalls... + + /// Executes the `CUSTOM_OP` precompile. + CUSTOM_OP = 0x00_01_01_2C, // Replace with the appropriate unique value +} +``` + +### Update the `from_u32` method +Ensure the `from_u32` method can map the unique value to the new `SyscallCode` variant. + +```rust +impl SyscallCode { + pub fn from_u32(value: u32) -> Self { + match value { + // Existing syscalls... + + 0x00_01_01_2C => SyscallCode::CUSTOM_OP, + _ => panic!("invalid syscall number: {}", value), + } + } + + // Other methods... +} +``` + +### Insert the New Syscall in the `default_syscall_map` +In the `default_syscall_map` function, register your new syscall by inserting it into the `syscall_map` with its corresponding chip. + +```rust +pub fn default_syscall_map() -> HashMap> { + + // Other syscall maps... + syscall_map.insert( + SyscallCode::CUSTOM_OP, + Arch::new(CustomOpChip::new()) + ) +} +``` + +## Write Unit Tests for the New Precompile +### Create a New SP1 Test Package +Create a new SP1 crate for your custom precompile test package inside the directory `sp1/tests`. An example `Cargo.toml` for this may look like +```toml +[workspace] +[package] +name = "custom-precompile-test" +version = "1.0.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" +``` +Then implement the tests and run `cargo prove build` to generate an ELF file. + +### Include teh ELF File in `program.rs` +In your main SP1 project, include teh generated ELF file by updating `program.rs`. +```rust +pub const CUSTOM_PRECOMPILE_ELF: &[u8] = + include_bytes!("path/to/generated/elf/file"); +// Other ELF files... +``` + +### Write Tests for Your Custom Precompile +Add tests that use this ELF file in your local SP1 project. +```rust +// /path/to/your/precompile/mod.rs + +mod air; + +pub use air::*; + +#[cfg(test)] +mod tests { + use crate::{ + io::SP1Stdin, + runtime::Program, + utils::{ + self, + run_test_io, + tests::CUSTOM_PRECOMPILE_ELF, + }, + }; + + #[test] + fn test_custom_precompile() { + utils::setup_logger(); + let program = Program::from(CUSTOM_PRECOMPILE_ELF); + run_test_io::>(program, SP1Stdin::new()).unwrap(); + } + + // Add additional tests as needed +} +``` +### Run Your Tests +Finally, run your test to verify that your custom precompile works as expected: +```bash +cargo test --release +``` diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs similarity index 75% rename from core/src/syscall/precompiles/edwards/ed_add.rs rename to crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs index 34e4746cd2..78633e269d 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs @@ -1,50 +1,38 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; -use std::fmt::Debug; -use std::marker::PhantomData; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; +use std::{fmt::Debug, marker::PhantomData}; use hashbrown::HashMap; use itertools::Itertools; -use num::BigUint; -use num::Zero; - -use p3_air::AirBuilder; -use p3_air::{Air, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_maybe_rayon::prelude::IntoParallelRefIterator; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSlice; +use num::{BigUint, Zero}; + +use crate::air::MemoryAirBuilder; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::{IntoParallelRefIterator, ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, EllipticCurveAddEvent, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + edwards::{ed25519::Ed25519BaseField, EdwardsParameters, NUM_LIMBS, WORDS_CURVE_POINT}, + params::FieldParameters, + AffinePoint, EllipticCurve, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, SP1AirBuilder}; -use super::{NUM_LIMBS, WORDS_CURVE_POINT}; -use crate::air::BaseAirBuilder; -use crate::air::MachineAir; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::memory::value_as_limbs; -use crate::memory::MemoryReadCols; -use crate::memory::MemoryWriteCols; -use crate::operations::field::field_den::FieldDenCols; -use crate::operations::field::field_inner_product::FieldInnerProductCols; -use crate::operations::field::field_op::FieldOpCols; -use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::FieldParameters; -use crate::runtime::ExecutionRecord; -use crate::runtime::Program; -use crate::runtime::Syscall; -use crate::runtime::SyscallCode; -use crate::syscall::precompiles::SyscallContext; -use crate::syscall::precompiles::{create_ec_add_event, ECAddEvent}; -use crate::utils::ec::edwards::ed25519::Ed25519BaseField; -use crate::utils::ec::edwards::EdwardsParameters; -use crate::utils::ec::AffinePoint; -use crate::utils::ec::EllipticCurve; -use crate::utils::limbs_from_prev_access; -use crate::utils::pad_rows; +use crate::{ + memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}, + operations::field::{ + field_den::FieldDenCols, field_inner_product::FieldInnerProductCols, field_op::FieldOpCols, + }, + utils::{limbs_from_prev_access, pad_rows}, +}; pub const NUM_ED_ADD_COLS: usize = size_of::>(); @@ -80,9 +68,7 @@ pub struct EdAddAssignChip { impl EdAddAssignChip { pub const fn new() -> Self { - Self { - _marker: PhantomData, - } + Self { _marker: PhantomData } } #[allow(clippy::too_many_arguments)] @@ -111,41 +97,17 @@ impl EdAddAssignChip { &[q_y.clone(), q_x.clone()], ); let x1_mul_y1 = - cols.x1_mul_y1 - .populate(record, shard, channel, &p_x, &p_y, FieldOperation::Mul); + cols.x1_mul_y1.populate(record, shard, channel, &p_x, &p_y, FieldOperation::Mul); let x2_mul_y2 = - cols.x2_mul_y2 - .populate(record, shard, channel, &q_x, &q_y, FieldOperation::Mul); - let f = cols.f.populate( - record, - shard, - channel, - &x1_mul_y1, - &x2_mul_y2, - FieldOperation::Mul, - ); + cols.x2_mul_y2.populate(record, shard, channel, &q_x, &q_y, FieldOperation::Mul); + let f = + cols.f.populate(record, shard, channel, &x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); let d = E::d_biguint(); - let d_mul_f = cols - .d_mul_f - .populate(record, shard, channel, &f, &d, FieldOperation::Mul); - - cols.x3_ins - .populate(record, shard, channel, &x3_numerator, &d_mul_f, true); - cols.y3_ins - .populate(record, shard, channel, &y3_numerator, &d_mul_f, false); - } -} - -impl Syscall for EdAddAssignChip { - fn num_extra_cycles(&self) -> u32 { - 1 - } + let d_mul_f = cols.d_mul_f.populate(record, shard, channel, &f, &d, FieldOperation::Mul); - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let event = create_ec_add_event::(rt, arg1, arg2); - rt.record_mut().ed_add_events.push(event); - None + cols.x3_ins.populate(record, shard, channel, &x3_numerator, &d_mul_f, true); + cols.y3_ins.populate(record, shard, channel, &y3_numerator, &d_mul_f, false); } } @@ -193,10 +155,8 @@ impl MachineAir for Ed }); // Convert the trace to a row major matrix. - let mut trace = RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_ED_ADD_COLS, - ); + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_ED_ADD_COLS); // Write the nonces to the trace. for i in 0..trace.height() { @@ -237,7 +197,7 @@ impl EdAddAssignChip { /// Create a row from an event. fn event_to_row( &self, - event: &ECAddEvent, + event: &EllipticCurveAddEvent, cols: &mut EdAddAssignCols, blu: &mut impl ByteRecord, ) { @@ -288,9 +248,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let x1 = limbs_from_prev_access(&local.p_access[0..8]); let x2 = limbs_from_prev_access(&local.q_access[0..8]); @@ -393,10 +351,9 @@ where builder .when(local.is_real) .assert_all_eq(local.x3_ins.result, p_access_vec[0..NUM_LIMBS].to_vec()); - builder.when(local.is_real).assert_all_eq( - local.y3_ins.result, - p_access_vec[NUM_LIMBS..NUM_LIMBS * 2].to_vec(), - ); + builder + .when(local.is_real) + .assert_all_eq(local.y3_ins.result, p_access_vec[NUM_LIMBS..NUM_LIMBS * 2].to_vec()); builder.eval_memory_access_slice( local.shard, @@ -431,22 +388,25 @@ where #[cfg(test)] mod tests { - use crate::stark::CpuProver; - use crate::utils; - use crate::utils::tests::{ED25519_ELF, ED_ADD_ELF}; - use crate::Program; + use sp1_core_executor::Program; + use sp1_stark::CpuProver; + + use crate::{ + utils, + utils::tests::{ED25519_ELF, ED_ADD_ELF}, + }; #[test] fn test_ed_add_simple() { utils::setup_logger(); - let program = Program::from(ED_ADD_ELF); + let program = Program::from(ED_ADD_ELF).unwrap(); utils::run_test::>(program).unwrap(); } #[test] fn test_ed25519_program() { utils::setup_logger(); - let program = Program::from(ED25519_ELF); + let program = Program::from(ED25519_ELF).unwrap(); utils::run_test::>(program).unwrap(); } } diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs similarity index 58% rename from core/src/syscall/precompiles/edwards/ed_decompress.rs rename to crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs index b708fa8126..63a73b2f0b 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs @@ -1,69 +1,36 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use std::marker::PhantomData; -use curve25519_dalek::edwards::CompressedEdwardsY; +use crate::air::MemoryAirBuilder; use generic_array::GenericArray; -use num::BigUint; -use num::One; -use num::Zero; +use num::{BigUint, One, Zero}; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use serde::Deserialize; -use serde::Serialize; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, EdDecompressEvent, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + edwards::{ + ed25519::{ed25519_sqrt, Ed25519BaseField}, + EdwardsParameters, WordsFieldElement, + }, + params::{limbs_from_vec, FieldParameters, Limbs}, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, SP1AirBuilder}; use typenum::U32; -use crate::air::BaseAirBuilder; -use crate::air::MachineAir; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::memory::MemoryReadCols; -use crate::memory::MemoryWriteCols; -use crate::operations::field::field_op::FieldOpCols; -use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::field_sqrt::FieldSqrtCols; -use crate::operations::field::params::Limbs; -use crate::operations::field::params::{limbs_from_vec, FieldParameters}; -use crate::operations::field::range::FieldLtCols; -use crate::runtime::ExecutionRecord; -use crate::runtime::MemoryReadRecord; -use crate::runtime::MemoryWriteRecord; -use crate::runtime::Program; -use crate::runtime::Syscall; -use crate::runtime::SyscallCode; -use crate::syscall::precompiles::SyscallContext; -use crate::utils::bytes_to_words_le; -use crate::utils::ec::edwards::ed25519::decompress; -use crate::utils::ec::edwards::ed25519::ed25519_sqrt; -use crate::utils::ec::edwards::ed25519::Ed25519BaseField; -use crate::utils::ec::edwards::EdwardsParameters; -use crate::utils::ec::COMPRESSED_POINT_BYTES; -use crate::utils::ec::NUM_BYTES_FIELD_ELEMENT; -use crate::utils::limbs_from_access; -use crate::utils::limbs_from_prev_access; -use crate::utils::pad_rows; -use crate::utils::words_to_bytes_le; - -use super::{WordsFieldElement, WORDS_FIELD_ELEMENT}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EdDecompressEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub ptr: u32, - pub sign: bool, - pub y_bytes: [u8; COMPRESSED_POINT_BYTES], - pub decompressed_x_bytes: [u8; NUM_BYTES_FIELD_ELEMENT], - pub x_memory_records: [MemoryWriteRecord; WORDS_FIELD_ELEMENT], - pub y_memory_records: [MemoryReadRecord; WORDS_FIELD_ELEMENT], -} +use crate::{ + memory::{MemoryReadCols, MemoryWriteCols}, + operations::field::{field_op::FieldOpCols, field_sqrt::FieldSqrtCols, range::FieldLtCols}, + utils::{limbs_from_access, limbs_from_prev_access, pad_rows}, +}; pub const NUM_ED_DECOMPRESS_COLS: usize = size_of::>(); @@ -107,11 +74,7 @@ impl EdDecompressCols { self.clk = F::from_canonical_u32(event.clk); self.ptr = F::from_canonical_u32(event.ptr); self.nonce = F::from_canonical_u32( - record - .nonce_lookup - .get(&event.lookup_id) - .copied() - .unwrap_or_default(), + record.nonce_lookup.get(&event.lookup_id).copied().unwrap_or_default(), ); self.sign = F::from_bool(event.sign); for i in 0..8 { @@ -141,14 +104,9 @@ impl EdDecompressCols { y: &BigUint, ) { let one = BigUint::one(); - self.y_range - .populate(blu_events, shard, channel, y, &Ed25519BaseField::modulus()); - let yy = self - .yy - .populate(blu_events, shard, channel, y, y, FieldOperation::Mul); - let u = self - .u - .populate(blu_events, shard, channel, &yy, &one, FieldOperation::Sub); + self.y_range.populate(blu_events, shard, channel, y, &Ed25519BaseField::modulus()); + let yy = self.yy.populate(blu_events, shard, channel, y, y, FieldOperation::Mul); + let u = self.u.populate(blu_events, shard, channel, &yy, &one, FieldOperation::Sub); let dyy = self.dyy.populate( blu_events, shard, @@ -157,23 +115,11 @@ impl EdDecompressCols { &yy, FieldOperation::Mul, ); - let v = self - .v - .populate(blu_events, shard, channel, &one, &dyy, FieldOperation::Add); + let v = self.v.populate(blu_events, shard, channel, &one, &dyy, FieldOperation::Add); let u_div_v = - self.u_div_v - .populate(blu_events, shard, channel, &u, &v, FieldOperation::Div); - let x = self - .x - .populate(blu_events, shard, channel, &u_div_v, ed25519_sqrt); - self.neg_x.populate( - blu_events, - shard, - channel, - &BigUint::zero(), - &x, - FieldOperation::Sub, - ); + self.u_div_v.populate(blu_events, shard, channel, &u, &v, FieldOperation::Div); + let x = self.x.populate(blu_events, shard, channel, &u_div_v, ed25519_sqrt); + self.neg_x.populate(blu_events, shard, channel, &BigUint::zero(), &x, FieldOperation::Sub); } } @@ -196,15 +142,7 @@ impl EdDecompressCols { self.channel, self.is_real, ); - self.yy.eval( - builder, - &y, - &y, - FieldOperation::Mul, - self.shard, - self.channel, - self.is_real, - ); + self.yy.eval(builder, &y, &y, FieldOperation::Mul, self.shard, self.channel, self.is_real); self.u.eval( builder, &self.yy.result, @@ -280,10 +218,7 @@ impl EdDecompressCols { // Constrain that the correct result is written into x. let x_limbs: Limbs = limbs_from_access(&self.x_access); - builder - .when(self.is_real) - .when(self.sign) - .assert_all_eq(self.neg_x.result, x_limbs); + builder.when(self.is_real).when(self.sign).assert_all_eq(self.neg_x.result, x_limbs); builder .when(self.is_real) .when_not(self.sign) @@ -307,73 +242,9 @@ pub struct EdDecompressChip { _phantom: PhantomData, } -impl Syscall for EdDecompressChip { - fn execute(&self, rt: &mut SyscallContext, arg1: u32, sign: u32) -> Option { - let start_clk = rt.clk; - let slice_ptr = arg1; - assert!(slice_ptr % 4 == 0, "Pointer must be 4-byte aligned."); - assert!(sign <= 1, "Sign bit must be 0 or 1."); - - let (y_memory_records_vec, y_vec) = rt.mr_slice( - slice_ptr + (COMPRESSED_POINT_BYTES as u32), - WORDS_FIELD_ELEMENT, - ); - let y_memory_records: [MemoryReadRecord; 8] = y_memory_records_vec.try_into().unwrap(); - - let sign_bool = sign != 0; - - let y_bytes: [u8; COMPRESSED_POINT_BYTES] = words_to_bytes_le(&y_vec); - - // Copy bytes into another array so we can modify the last byte and make CompressedEdwardsY, - // which we'll use to compute the expected X. - // Re-insert sign bit into last bit of Y for CompressedEdwardsY format - let mut compressed_edwards_y: [u8; COMPRESSED_POINT_BYTES] = y_bytes; - compressed_edwards_y[compressed_edwards_y.len() - 1] &= 0b0111_1111; - compressed_edwards_y[compressed_edwards_y.len() - 1] |= (sign as u8) << 7; - - // Compute actual decompressed X - let compressed_y = CompressedEdwardsY(compressed_edwards_y); - let decompressed = decompress(&compressed_y); - - let mut decompressed_x_bytes = decompressed.x.to_bytes_le(); - decompressed_x_bytes.resize(32, 0u8); - let decompressed_x_words: [u32; WORDS_FIELD_ELEMENT] = - bytes_to_words_le(&decompressed_x_bytes); - - // Write decompressed X into slice - let x_memory_records_vec = rt.mw_slice(slice_ptr, &decompressed_x_words); - let x_memory_records: [MemoryWriteRecord; 8] = x_memory_records_vec.try_into().unwrap(); - - let lookup_id = rt.syscall_lookup_id; - let shard = rt.current_shard(); - let channel = rt.current_channel(); - rt.record_mut() - .ed_decompress_events - .push(EdDecompressEvent { - lookup_id, - shard, - channel, - clk: start_clk, - ptr: slice_ptr, - sign: sign_bool, - y_bytes, - decompressed_x_bytes: decompressed_x_bytes.try_into().unwrap(), - x_memory_records, - y_memory_records, - }); - None - } - - fn num_extra_cycles(&self) -> u32 { - 0 - } -} - impl EdDecompressChip { pub const fn new() -> Self { - Self { - _phantom: PhantomData, - } + Self { _phantom: PhantomData } } } @@ -450,9 +321,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); local.eval::(builder); } @@ -460,16 +329,15 @@ where #[cfg(test)] pub mod tests { - use crate::{ - runtime::Program, - stark::CpuProver, - utils::{self, tests::ED_DECOMPRESS_ELF}, - }; + use sp1_core_executor::Program; + use sp1_stark::CpuProver; + + use crate::utils::{self, tests::ED_DECOMPRESS_ELF}; #[test] fn test_ed_decompress() { utils::setup_logger(); - let program = Program::from(ED_DECOMPRESS_ELF); + let program = Program::from(ED_DECOMPRESS_ELF).unwrap(); utils::run_test::>(program).unwrap(); } } diff --git a/crates/core/machine/src/syscall/precompiles/edwards/mod.rs b/crates/core/machine/src/syscall/precompiles/edwards/mod.rs new file mode 100644 index 0000000000..dadf241f78 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/edwards/mod.rs @@ -0,0 +1,5 @@ +mod ed_add; +mod ed_decompress; + +pub use ed_add::*; +pub use ed_decompress::*; diff --git a/crates/core/machine/src/syscall/precompiles/fptower/fp.rs b/crates/core/machine/src/syscall/precompiles/fptower/fp.rs new file mode 100644 index 0000000000..a87170afc2 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/fptower/fp.rs @@ -0,0 +1,286 @@ +use std::{ + borrow::{Borrow, BorrowMut}, + marker::PhantomData, + mem::size_of, +}; + +use crate::air::MemoryAirBuilder; +use generic_array::GenericArray; +use itertools::Itertools; +use num::{BigUint, Zero}; +use p3_air::{Air, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{Limbs, NumLimbs}, + weierstrass::{FieldType, FpOpField}, +}; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, Polynomial, SP1AirBuilder}; + +use crate::{ + memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, + utils::{limbs_from_prev_access, pad_rows, words_to_bytes_le_vec}, +}; + +pub const fn num_fp_cols() -> usize { + size_of::>() +} + +pub struct FpOpChip

{ + _marker: PhantomData

, +} + +/// A set of columns for the FpAdd operation. +#[derive(Debug, Clone, AlignedBorrow)] +#[repr(C)] +pub struct FpOpCols { + pub is_real: T, + pub shard: T, + pub channel: T, + pub nonce: T, + pub clk: T, + pub is_add: T, + pub is_sub: T, + pub is_mul: T, + pub x_ptr: T, + pub y_ptr: T, + pub x_access: GenericArray, P::WordsFieldElement>, + pub y_access: GenericArray, P::WordsFieldElement>, + pub(crate) output: FieldOpCols, +} + +impl FpOpChip

{ + pub const fn new() -> Self { + Self { _marker: PhantomData } + } + + #[allow(clippy::too_many_arguments)] + fn populate_field_ops( + blu_events: &mut Vec, + shard: u32, + channel: u8, + cols: &mut FpOpCols, + p: BigUint, + q: BigUint, + op: FieldOperation, + ) { + let modulus_bytes = P::MODULUS; + let modulus = BigUint::from_bytes_le(modulus_bytes); + cols.output.populate_with_modulus(blu_events, shard, channel, &p, &q, &modulus, op); + } +} + +impl MachineAir for FpOpChip

{ + type Record = ExecutionRecord; + + type Program = Program; + + fn name(&self) -> String { + match P::FIELD_TYPE { + FieldType::Bn254 => "Bn254FpOpAssign".to_string(), + FieldType::Bls12381 => "Bls12381FpOpAssign".to_string(), + } + } + + fn generate_trace(&self, input: &Self::Record, output: &mut Self::Record) -> RowMajorMatrix { + let events = match P::FIELD_TYPE { + FieldType::Bn254 => &input.bn254_fp_events, + FieldType::Bls12381 => &input.bls12381_fp_events, + }; + + let mut rows = Vec::new(); + let mut new_byte_lookup_events = Vec::new(); + + for i in 0..events.len() { + let event = &events[i]; + + let mut row = vec![F::zero(); num_fp_cols::

()]; + let cols: &mut FpOpCols = row.as_mut_slice().borrow_mut(); + + let modulus = &BigUint::from_bytes_le(P::MODULUS); + let p = BigUint::from_bytes_le(&words_to_bytes_le_vec(&event.x)) % modulus; + let q = BigUint::from_bytes_le(&words_to_bytes_le_vec(&event.y)) % modulus; + + cols.is_add = F::from_canonical_u8((event.op == FieldOperation::Add) as u8); + cols.is_sub = F::from_canonical_u8((event.op == FieldOperation::Sub) as u8); + cols.is_mul = F::from_canonical_u8((event.op == FieldOperation::Mul) as u8); + cols.is_real = F::one(); + cols.shard = F::from_canonical_u32(event.shard); + cols.channel = F::from_canonical_u8(event.channel); + cols.clk = F::from_canonical_u32(event.clk); + cols.x_ptr = F::from_canonical_u32(event.x_ptr); + cols.y_ptr = F::from_canonical_u32(event.y_ptr); + + Self::populate_field_ops( + &mut new_byte_lookup_events, + event.shard, + event.channel, + cols, + p, + q, + event.op, + ); + + // Populate the memory access columns. + for i in 0..cols.y_access.len() { + cols.y_access[i].populate( + event.channel, + event.y_memory_records[i], + &mut new_byte_lookup_events, + ); + } + for i in 0..cols.x_access.len() { + cols.x_access[i].populate( + event.channel, + event.x_memory_records[i], + &mut new_byte_lookup_events, + ); + } + rows.push(row) + } + + output.add_byte_lookup_events(new_byte_lookup_events); + + pad_rows(&mut rows, || { + let mut row = vec![F::zero(); num_fp_cols::

()]; + let cols: &mut FpOpCols = row.as_mut_slice().borrow_mut(); + let zero = BigUint::zero(); + cols.is_add = F::from_canonical_u8(1); + Self::populate_field_ops( + &mut vec![], + 0, + 0, + cols, + zero.clone(), + zero, + FieldOperation::Add, + ); + row + }); + + // Convert the trace to a row major matrix. + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), num_fp_cols::

()); + + // Write the nonces to the trace. + for i in 0..trace.height() { + let cols: &mut FpOpCols = + trace.values[i * num_fp_cols::

()..(i + 1) * num_fp_cols::

()].borrow_mut(); + cols.nonce = F::from_canonical_usize(i); + } + + trace + } + + fn included(&self, shard: &Self::Record) -> bool { + match P::FIELD_TYPE { + FieldType::Bn254 => !shard.bn254_fp_events.is_empty(), + FieldType::Bls12381 => !shard.bls12381_fp_events.is_empty(), + } + } +} + +impl BaseAir for FpOpChip

{ + fn width(&self) -> usize { + num_fp_cols::

() + } +} + +impl Air for FpOpChip

+where + AB: SP1AirBuilder, + Limbs::Limbs>: Copy, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &FpOpCols = (*local).borrow(); + + // Check that operations flags are boolean. + builder.assert_bool(local.is_add); + builder.assert_bool(local.is_sub); + builder.assert_bool(local.is_mul); + // Check that only one of them is set. + builder.assert_eq(local.is_add + local.is_sub + local.is_mul, AB::Expr::one()); + + let p = limbs_from_prev_access(&local.x_access); + let q = limbs_from_prev_access(&local.y_access); + + let modulus_coeffs = + P::MODULUS.iter().map(|&limbs| AB::Expr::from_canonical_u8(limbs)).collect_vec(); + let p_modulus = Polynomial::from_coefficients(&modulus_coeffs); + + local.output.eval_variable( + builder, + &p, + &q, + &p_modulus, + local.is_add, + local.is_sub, + local.is_mul, + AB::F::zero(), + local.shard, + local.channel, + local.is_real, + ); + + builder + .when(local.is_real) + .assert_all_eq(local.output.result, value_as_limbs(&local.x_access)); + + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk.into(), + local.y_ptr, + &local.y_access, + local.is_real, + ); + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk + AB::F::from_canonical_u32(1), /* We read p at +1 since p, q could be the + * same. */ + local.x_ptr, + &local.x_access, + local.is_real, + ); + + // Select the correct syscall id based on the operation flags. + // + // *Remark*: If support for division is added, we will need to add the division syscall id. + let (add_syscall_id, sub_syscall_id, mul_syscall_id) = match P::FIELD_TYPE { + FieldType::Bn254 => ( + AB::F::from_canonical_u32(SyscallCode::BN254_FP_ADD.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BN254_FP_SUB.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BN254_FP_MUL.syscall_id()), + ), + FieldType::Bls12381 => ( + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP_ADD.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP_SUB.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP_MUL.syscall_id()), + ), + }; + let syscall_id_felt = local.is_add * add_syscall_id + + local.is_sub * sub_syscall_id + + local.is_mul * mul_syscall_id; + + builder.receive_syscall( + local.shard, + local.channel, + local.clk, + local.nonce, + syscall_id_felt, + local.x_ptr, + local.y_ptr, + local.is_real, + ); + } +} diff --git a/crates/core/machine/src/syscall/precompiles/fptower/fp2_addsub.rs b/crates/core/machine/src/syscall/precompiles/fptower/fp2_addsub.rs new file mode 100644 index 0000000000..5024fad6c4 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/fptower/fp2_addsub.rs @@ -0,0 +1,317 @@ +use std::{ + borrow::{Borrow, BorrowMut}, + marker::PhantomData, + mem::size_of, +}; + +use crate::air::MemoryAirBuilder; +use generic_array::GenericArray; +use itertools::Itertools; +use num::{BigUint, Zero}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{Limbs, NumLimbs}, + weierstrass::{FieldType, FpOpField}, +}; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, Polynomial, SP1AirBuilder}; +use typenum::Unsigned; + +use crate::{ + memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, + utils::{limbs_from_prev_access, pad_rows, words_to_bytes_le_vec}, +}; + +pub const fn num_fp2_addsub_cols() -> usize { + size_of::>() +} + +/// A set of columns for the Fp2AddSub operation. +#[derive(Debug, Clone, AlignedBorrow)] +#[repr(C)] +pub struct Fp2AddSubAssignCols { + pub is_real: T, + pub shard: T, + pub channel: T, + pub nonce: T, + pub clk: T, + pub is_add: T, + pub x_ptr: T, + pub y_ptr: T, + pub x_access: GenericArray, P::WordsCurvePoint>, + pub y_access: GenericArray, P::WordsCurvePoint>, + pub(crate) c0: FieldOpCols, + pub(crate) c1: FieldOpCols, +} + +pub struct Fp2AddSubAssignChip

{ + _marker: PhantomData

, +} + +impl Fp2AddSubAssignChip

{ + pub const fn new() -> Self { + Self { _marker: PhantomData } + } + + #[allow(clippy::too_many_arguments)] + fn populate_field_ops( + blu_events: &mut Vec, + shard: u32, + channel: u8, + cols: &mut Fp2AddSubAssignCols, + p_x: BigUint, + p_y: BigUint, + q_x: BigUint, + q_y: BigUint, + op: FieldOperation, + ) { + let modulus_bytes = P::MODULUS; + let modulus = BigUint::from_bytes_le(modulus_bytes); + cols.c0.populate_with_modulus(blu_events, shard, channel, &p_x, &q_x, &modulus, op); + cols.c1.populate_with_modulus(blu_events, shard, channel, &p_y, &q_y, &modulus, op); + } +} + +impl MachineAir for Fp2AddSubAssignChip

{ + type Record = ExecutionRecord; + + type Program = Program; + + fn name(&self) -> String { + match P::FIELD_TYPE { + FieldType::Bn254 => "Bn254Fp2AddSubAssign".to_string(), + FieldType::Bls12381 => "Bls12831Fp2AddSubAssign".to_string(), + } + } + + fn generate_trace(&self, input: &Self::Record, output: &mut Self::Record) -> RowMajorMatrix { + let events = match P::FIELD_TYPE { + FieldType::Bn254 => &input.bn254_fp2_addsub_events, + FieldType::Bls12381 => &input.bls12381_fp2_addsub_events, + }; + + let mut rows = Vec::new(); + let mut new_byte_lookup_events = Vec::new(); + + for i in 0..events.len() { + let event = &events[i]; + + let mut row = vec![F::zero(); num_fp2_addsub_cols::

()]; + let cols: &mut Fp2AddSubAssignCols = row.as_mut_slice().borrow_mut(); + + let p = &event.x; + let q = &event.y; + let p_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&p[..p.len() / 2])); + let p_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&p[p.len() / 2..])); + let q_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&q[..q.len() / 2])); + let q_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&q[q.len() / 2..])); + + cols.is_real = F::one(); + cols.is_add = F::from_bool(event.op == FieldOperation::Add); + cols.shard = F::from_canonical_u32(event.shard); + cols.channel = F::from_canonical_u8(event.channel); + cols.clk = F::from_canonical_u32(event.clk); + cols.x_ptr = F::from_canonical_u32(event.x_ptr); + cols.y_ptr = F::from_canonical_u32(event.y_ptr); + + Self::populate_field_ops( + &mut new_byte_lookup_events, + event.shard, + event.channel, + cols, + p_x, + p_y, + q_x, + q_y, + event.op, + ); + + // Populate the memory access columns. + for i in 0..cols.y_access.len() { + cols.y_access[i].populate( + event.channel, + event.y_memory_records[i], + &mut new_byte_lookup_events, + ); + } + for i in 0..cols.x_access.len() { + cols.x_access[i].populate( + event.channel, + event.x_memory_records[i], + &mut new_byte_lookup_events, + ); + } + rows.push(row) + } + + output.add_byte_lookup_events(new_byte_lookup_events); + + pad_rows(&mut rows, || { + let mut row = vec![F::zero(); num_fp2_addsub_cols::

()]; + let cols: &mut Fp2AddSubAssignCols = row.as_mut_slice().borrow_mut(); + cols.is_add = F::one(); + let zero = BigUint::zero(); + Self::populate_field_ops( + &mut vec![], + 0, + 0, + cols, + zero.clone(), + zero.clone(), + zero.clone(), + zero, + FieldOperation::Add, + ); + row + }); + + // Convert the trace to a row major matrix. + let mut trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect::>(), + num_fp2_addsub_cols::

(), + ); + + // Write the nonces to the trace. + for i in 0..trace.height() { + let cols: &mut Fp2AddSubAssignCols = trace.values + [i * num_fp2_addsub_cols::

()..(i + 1) * num_fp2_addsub_cols::

()] + .borrow_mut(); + cols.nonce = F::from_canonical_usize(i); + } + + trace + } + + fn included(&self, shard: &Self::Record) -> bool { + match P::FIELD_TYPE { + FieldType::Bn254 => !shard.bn254_fp2_addsub_events.is_empty(), + FieldType::Bls12381 => !shard.bls12381_fp2_addsub_events.is_empty(), + } + } +} + +impl BaseAir for Fp2AddSubAssignChip

{ + fn width(&self) -> usize { + num_fp2_addsub_cols::

() + } +} + +impl Air for Fp2AddSubAssignChip

+where + AB: SP1AirBuilder, + Limbs::Limbs>: Copy, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &Fp2AddSubAssignCols = (*local).borrow(); + let next = main.row_slice(1); + let next: &Fp2AddSubAssignCols = (*next).borrow(); + + // Constrain the `is_add` flag to be boolean. + builder.assert_bool(local.is_add); + + builder.when_first_row().assert_zero(local.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); + let num_words_field_element =

::Limbs::USIZE / 4; + + let p_x = limbs_from_prev_access(&local.x_access[0..num_words_field_element]); + let p_y = limbs_from_prev_access(&local.x_access[num_words_field_element..]); + + let q_x = limbs_from_prev_access(&local.y_access[0..num_words_field_element]); + let q_y = limbs_from_prev_access(&local.y_access[num_words_field_element..]); + + let modulus_coeffs = + P::MODULUS.iter().map(|&limbs| AB::Expr::from_canonical_u8(limbs)).collect_vec(); + let p_modulus = Polynomial::from_coefficients(&modulus_coeffs); + + { + local.c0.eval_variable( + builder, + &p_x, + &q_x, + &p_modulus, + local.is_add, + AB::Expr::one() - local.is_add, + AB::F::zero(), + AB::F::zero(), + local.shard, + local.channel, + local.is_real, + ); + + local.c1.eval_variable( + builder, + &p_y, + &q_y, + &p_modulus, + local.is_add, + AB::Expr::one() - local.is_add, + AB::F::zero(), + AB::F::zero(), + local.shard, + local.channel, + local.is_real, + ); + } + + builder.when(local.is_real).assert_all_eq( + local.c0.result, + value_as_limbs(&local.x_access[0..num_words_field_element]), + ); + builder.when(local.is_real).assert_all_eq( + local.c1.result, + value_as_limbs(&local.x_access[num_words_field_element..]), + ); + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk.into(), + local.y_ptr, + &local.y_access, + local.is_real, + ); + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk + AB::F::from_canonical_u32(1), /* We read p at +1 since p, q could be the + * same. */ + local.x_ptr, + &local.x_access, + local.is_real, + ); + + let (add_syscall_id, sub_syscall_id) = match P::FIELD_TYPE { + FieldType::Bn254 => ( + AB::F::from_canonical_u32(SyscallCode::BN254_FP2_ADD.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BN254_FP2_SUB.syscall_id()), + ), + FieldType::Bls12381 => ( + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP2_ADD.syscall_id()), + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP2_SUB.syscall_id()), + ), + }; + + let syscall_id_felt = + local.is_add * add_syscall_id + (AB::Expr::one() - local.is_add) * sub_syscall_id; + + builder.receive_syscall( + local.shard, + local.channel, + local.clk, + local.nonce, + syscall_id_felt, + local.x_ptr, + local.y_ptr, + local.is_real, + ); + } +} diff --git a/crates/core/machine/src/syscall/precompiles/fptower/fp2_mul.rs b/crates/core/machine/src/syscall/precompiles/fptower/fp2_mul.rs new file mode 100644 index 0000000000..7987986011 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/fptower/fp2_mul.rs @@ -0,0 +1,398 @@ +use std::{ + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; + +use crate::air::MemoryAirBuilder; +use generic_array::GenericArray; +use itertools::Itertools; +use num::{BigUint, Zero}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{FieldParameters, Limbs, NumLimbs, NumWords}, + weierstrass::{FieldType, FpOpField}, +}; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, Polynomial, SP1AirBuilder}; +use std::mem::size_of; +use typenum::Unsigned; + +use crate::{ + memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, + utils::{limbs_from_prev_access, pad_rows, words_to_bytes_le_vec}, +}; + +pub const fn num_fp2_mul_cols() -> usize { + size_of::>() +} + +/// A set of columns for the Fp2Mul operation. +#[derive(Debug, Clone, AlignedBorrow)] +#[repr(C)] +pub struct Fp2MulAssignCols { + pub is_real: T, + pub shard: T, + pub channel: T, + pub nonce: T, + pub clk: T, + pub x_ptr: T, + pub y_ptr: T, + pub x_access: GenericArray, P::WordsCurvePoint>, + pub y_access: GenericArray, P::WordsCurvePoint>, + pub(crate) a0_mul_b0: FieldOpCols, + pub(crate) a1_mul_b1: FieldOpCols, + pub(crate) a0_mul_b1: FieldOpCols, + pub(crate) a1_mul_b0: FieldOpCols, + pub(crate) c0: FieldOpCols, + pub(crate) c1: FieldOpCols, +} + +#[derive(Default)] +pub struct Fp2MulAssignChip

{ + _marker: PhantomData

, +} + +impl Fp2MulAssignChip

{ + pub const fn new() -> Self { + Self { _marker: PhantomData } + } + + #[allow(clippy::too_many_arguments)] + fn populate_field_ops( + blu_events: &mut Vec, + shard: u32, + channel: u8, + cols: &mut Fp2MulAssignCols, + p_x: BigUint, + p_y: BigUint, + q_x: BigUint, + q_y: BigUint, + ) { + let modulus_bytes = P::MODULUS; + let modulus = BigUint::from_bytes_le(modulus_bytes); + let a0_mul_b0 = cols.a0_mul_b0.populate_with_modulus( + blu_events, + shard, + channel, + &p_x, + &q_x, + &modulus, + FieldOperation::Mul, + ); + let a1_mul_b1 = cols.a1_mul_b1.populate_with_modulus( + blu_events, + shard, + channel, + &p_y, + &q_y, + &modulus, + FieldOperation::Mul, + ); + let a0_mul_b1 = cols.a0_mul_b1.populate_with_modulus( + blu_events, + shard, + channel, + &p_x, + &q_y, + &modulus, + FieldOperation::Mul, + ); + let a1_mul_b0 = cols.a1_mul_b0.populate_with_modulus( + blu_events, + shard, + channel, + &p_y, + &q_x, + &modulus, + FieldOperation::Mul, + ); + cols.c0.populate_with_modulus( + blu_events, + shard, + channel, + &a0_mul_b0, + &a1_mul_b1, + &modulus, + FieldOperation::Sub, + ); + cols.c1.populate_with_modulus( + blu_events, + shard, + channel, + &a0_mul_b1, + &a1_mul_b0, + &modulus, + FieldOperation::Add, + ); + } +} + +impl MachineAir for Fp2MulAssignChip

{ + type Record = ExecutionRecord; + + type Program = Program; + + fn name(&self) -> String { + match P::FIELD_TYPE { + FieldType::Bn254 => "Bn254Fp2MulAssign".to_string(), + FieldType::Bls12381 => "Bls12831Fp2MulAssign".to_string(), + } + } + + fn generate_trace(&self, input: &Self::Record, output: &mut Self::Record) -> RowMajorMatrix { + let events = match P::FIELD_TYPE { + FieldType::Bn254 => &input.bn254_fp2_mul_events, + FieldType::Bls12381 => &input.bls12381_fp2_mul_events, + }; + + let mut rows = Vec::new(); + let mut new_byte_lookup_events = Vec::new(); + + for i in 0..events.len() { + let event = &events[i]; + let mut row = vec![F::zero(); num_fp2_mul_cols::

()]; + let cols: &mut Fp2MulAssignCols = row.as_mut_slice().borrow_mut(); + + let p = &event.x; + let q = &event.y; + let p_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&p[..p.len() / 2])); + let p_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&p[p.len() / 2..])); + let q_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&q[..q.len() / 2])); + let q_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&q[q.len() / 2..])); + + cols.is_real = F::one(); + cols.shard = F::from_canonical_u32(event.shard); + cols.channel = F::from_canonical_u8(event.channel); + cols.clk = F::from_canonical_u32(event.clk); + cols.x_ptr = F::from_canonical_u32(event.x_ptr); + cols.y_ptr = F::from_canonical_u32(event.y_ptr); + + Self::populate_field_ops( + &mut new_byte_lookup_events, + event.shard, + event.channel, + cols, + p_x, + p_y, + q_x, + q_y, + ); + + // Populate the memory access columns. + for i in 0..cols.y_access.len() { + cols.y_access[i].populate( + event.channel, + event.y_memory_records[i], + &mut new_byte_lookup_events, + ); + } + for i in 0..cols.x_access.len() { + cols.x_access[i].populate( + event.channel, + event.x_memory_records[i], + &mut new_byte_lookup_events, + ); + } + rows.push(row) + } + + output.add_byte_lookup_events(new_byte_lookup_events); + + pad_rows(&mut rows, || { + let mut row = vec![F::zero(); num_fp2_mul_cols::

()]; + let cols: &mut Fp2MulAssignCols = row.as_mut_slice().borrow_mut(); + let zero = BigUint::zero(); + Self::populate_field_ops( + &mut vec![], + 0, + 0, + cols, + zero.clone(), + zero.clone(), + zero.clone(), + zero, + ); + row + }); + + // Convert the trace to a row major matrix. + let mut trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect::>(), + num_fp2_mul_cols::

(), + ); + + // Write the nonces to the trace. + for i in 0..trace.height() { + let cols: &mut Fp2MulAssignCols = trace.values + [i * num_fp2_mul_cols::

()..(i + 1) * num_fp2_mul_cols::

()] + .borrow_mut(); + cols.nonce = F::from_canonical_usize(i); + } + + trace + } + + fn included(&self, shard: &Self::Record) -> bool { + match P::FIELD_TYPE { + FieldType::Bn254 => !shard.bn254_fp2_mul_events.is_empty(), + FieldType::Bls12381 => !shard.bls12381_fp2_mul_events.is_empty(), + } + } +} + +impl BaseAir for Fp2MulAssignChip

{ + fn width(&self) -> usize { + num_fp2_mul_cols::

() + } +} + +impl Air for Fp2MulAssignChip

+where + AB: SP1AirBuilder, + Limbs::Limbs>: Copy, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &Fp2MulAssignCols = (*local).borrow(); + let next = main.row_slice(1); + let next: &Fp2MulAssignCols = (*next).borrow(); + + builder.when_first_row().assert_zero(local.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); + let num_words_field_element =

::Limbs::USIZE / 4; + + let p_x = limbs_from_prev_access(&local.x_access[0..num_words_field_element]); + let p_y = limbs_from_prev_access(&local.x_access[num_words_field_element..]); + + let q_x = limbs_from_prev_access(&local.y_access[0..num_words_field_element]); + let q_y = limbs_from_prev_access(&local.y_access[num_words_field_element..]); + + let modulus_coeffs = + P::MODULUS.iter().map(|&limbs| AB::Expr::from_canonical_u8(limbs)).collect_vec(); + let p_modulus = Polynomial::from_coefficients(&modulus_coeffs); + + { + local.a0_mul_b0.eval_with_modulus( + builder, + &p_x, + &q_x, + &p_modulus, + FieldOperation::Mul, + local.shard, + local.channel, + local.is_real, + ); + + local.a1_mul_b1.eval_with_modulus( + builder, + &p_y, + &q_y, + &p_modulus, + FieldOperation::Mul, + local.shard, + local.channel, + local.is_real, + ); + + local.c0.eval_with_modulus( + builder, + &local.a0_mul_b0.result, + &local.a1_mul_b1.result, + &p_modulus, + FieldOperation::Sub, + local.shard, + local.channel, + local.is_real, + ); + } + + { + local.a0_mul_b1.eval_with_modulus( + builder, + &p_x, + &q_y, + &p_modulus, + FieldOperation::Mul, + local.shard, + local.channel, + local.is_real, + ); + + local.a1_mul_b0.eval_with_modulus( + builder, + &p_y, + &q_x, + &p_modulus, + FieldOperation::Mul, + local.shard, + local.channel, + local.is_real, + ); + + local.c1.eval_with_modulus( + builder, + &local.a0_mul_b1.result, + &local.a1_mul_b0.result, + &p_modulus, + FieldOperation::Add, + local.shard, + local.channel, + local.is_real, + ); + } + + builder.when(local.is_real).assert_all_eq( + local.c0.result, + value_as_limbs(&local.x_access[0..num_words_field_element]), + ); + builder.when(local.is_real).assert_all_eq( + local.c1.result, + value_as_limbs(&local.x_access[num_words_field_element..]), + ); + + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk.into(), + local.y_ptr, + &local.y_access, + local.is_real, + ); + builder.eval_memory_access_slice( + local.shard, + local.channel, + local.clk + AB::F::from_canonical_u32(1), /* We read p at +1 since p, q could be the + * same. */ + local.x_ptr, + &local.x_access, + local.is_real, + ); + + let syscall_id_felt = match P::FIELD_TYPE { + FieldType::Bn254 => AB::F::from_canonical_u32(SyscallCode::BN254_FP2_MUL.syscall_id()), + FieldType::Bls12381 => { + AB::F::from_canonical_u32(SyscallCode::BLS12381_FP2_MUL.syscall_id()) + } + }; + + builder.receive_syscall( + local.shard, + local.channel, + local.clk, + local.nonce, + syscall_id_felt, + local.x_ptr, + local.y_ptr, + local.is_real, + ); + } +} diff --git a/crates/core/machine/src/syscall/precompiles/fptower/mod.rs b/crates/core/machine/src/syscall/precompiles/fptower/mod.rs new file mode 100644 index 0000000000..f9aa9d26e7 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/fptower/mod.rs @@ -0,0 +1,64 @@ +mod fp; +mod fp2_addsub; +mod fp2_mul; + +pub use fp::*; +pub use fp2_addsub::*; +pub use fp2_mul::*; + +#[cfg(test)] +mod tests { + use sp1_stark::CpuProver; + + use sp1_core_executor::{ + programs::tests::{ + BLS12381_FP2_ADDSUB_ELF, BLS12381_FP2_MUL_ELF, BLS12381_FP_ELF, BN254_FP2_ADDSUB_ELF, + BN254_FP2_MUL_ELF, BN254_FP_ELF, + }, + Program, + }; + + use crate::utils; + + #[test] + fn test_bls12381_fp() { + utils::setup_logger(); + let program = Program::from(BLS12381_FP_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } + + #[test] + fn test_bls12381_fp2_addsub() { + utils::setup_logger(); + let program = Program::from(BLS12381_FP2_ADDSUB_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } + + #[test] + fn test_bls12381_fp2_mul() { + utils::setup_logger(); + let program = Program::from(BLS12381_FP2_MUL_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } + + #[test] + fn test_bn254_fp() { + utils::setup_logger(); + let program = Program::from(BN254_FP_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } + + #[test] + fn test_bn254_fp2_addsub() { + utils::setup_logger(); + let program = Program::from(BN254_FP2_ADDSUB_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } + + #[test] + fn test_bn254_fp2_mul() { + utils::setup_logger(); + let program = Program::from(BN254_FP2_MUL_ELF).unwrap(); + utils::run_test::>(program).unwrap(); + } +} diff --git a/core/src/syscall/precompiles/keccak256/air.rs b/crates/core/machine/src/syscall/precompiles/keccak256/air.rs similarity index 83% rename from core/src/syscall/precompiles/keccak256/air.rs rename to crates/core/machine/src/syscall/precompiles/keccak256/air.rs index 2e70c20d0a..4a17ea1b3c 100644 --- a/core/src/syscall/precompiles/keccak256/air.rs +++ b/crates/core/machine/src/syscall/precompiles/keccak256/air.rs @@ -4,15 +4,16 @@ use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::AbstractField; use p3_keccak_air::{KeccakAir, NUM_KECCAK_COLS, NUM_ROUNDS, U64_LIMBS}; use p3_matrix::Matrix; +use sp1_core_executor::syscalls::SyscallCode; +use sp1_stark::air::{SP1AirBuilder, SubAirBuilder}; use super::{ columns::{KeccakMemCols, NUM_KECCAK_MEM_COLS}, KeccakPermuteChip, STATE_NUM_WORDS, STATE_SIZE, }; use crate::{ - air::{SP1AirBuilder, SubAirBuilder, WordAirBuilder}, + air::{MemoryAirBuilder, WordAirBuilder}, memory::MemoryCols, - runtime::SyscallCode, }; impl BaseAir for KeccakPermuteChip { @@ -34,29 +35,22 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let first_step = local.keccak.step_flags[0]; let final_step = local.keccak.step_flags[NUM_ROUNDS - 1]; let not_final_step = AB::Expr::one() - final_step; // Constrain memory in the first and last cycles. - builder.assert_eq( - (first_step + final_step) * local.is_real, - local.do_memory_check, - ); + builder.assert_eq((first_step + final_step) * local.is_real, local.do_memory_check); // Constrain memory for i in 0..STATE_NUM_WORDS as u32 { // At the first cycle, verify that the memory has not changed since it's a memory read. - builder - .when(local.keccak.step_flags[0] * local.is_real) - .assert_word_eq( - *local.state_mem[i as usize].value(), - *local.state_mem[i as usize].prev_value(), - ); + builder.when(local.keccak.step_flags[0] * local.is_real).assert_word_eq( + *local.state_mem[i as usize].value(), + *local.state_mem[i as usize].prev_value(), + ); builder.eval_memory_access( local.shard, @@ -94,8 +88,8 @@ where // ensures that the table does not end abruptly. builder.when_last_row().assert_zero(local.is_real); - // Verify that local.a values are equal to the memory values in the 0 and 23rd rows of each cycle - // Memory values are 32 bit values (encoded as 4 8-bit columns). + // Verify that local.a values are equal to the memory values in the 0 and 23rd rows of each + // cycle Memory values are 32 bit values (encoded as 4 8-bit columns). // local.a values are 64 bit values (encoded as 4 16-bit columns). let expr_2_pow_8 = AB::Expr::from_canonical_u32(2u32.pow(8)); for i in 0..STATE_SIZE as u32 { @@ -120,13 +114,12 @@ where .assert_eq(memory_limbs[i].clone(), a_value_limbs[i]); } - // On a final step row, verify memory matches with local.p3_keccak_cols.a_prime_prime_prime + // On a final step row, verify memory matches with + // local.p3_keccak_cols.a_prime_prime_prime for i in 0..U64_LIMBS { builder.when(final_step * local.is_real).assert_eq( memory_limbs[i].clone(), - local - .keccak - .a_prime_prime_prime(y_idx as usize, x_idx as usize, i), + local.keccak.a_prime_prime_prime(y_idx as usize, x_idx as usize, i), ) } } @@ -151,14 +144,17 @@ where #[cfg(test)] mod test { - use crate::io::{SP1PublicValues, SP1Stdin}; - use crate::runtime::Program; - use crate::stark::{CpuProver, RiscvAir, StarkGenericConfig}; - use crate::utils::SP1CoreOpts; - use crate::utils::{prove, setup_logger, tests::KECCAK256_ELF, BabyBearPoseidon2}; - - use rand::Rng; - use rand::SeedableRng; + use crate::{ + io::{SP1PublicValues, SP1Stdin}, + riscv::RiscvAir, + utils::{prove, setup_logger, tests::KECCAK256_ELF}, + }; + + use rand::{Rng, SeedableRng}; + use sp1_core_executor::Program; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, SP1CoreOpts, StarkGenericConfig, + }; use tiny_keccak::Hasher; const NUM_TEST_CASES: usize = 45; @@ -189,7 +185,7 @@ mod test { let config = BabyBearPoseidon2::new(); - let program = Program::from(KECCAK256_ELF); + let program = Program::from(KECCAK256_ELF).unwrap(); let (proof, public_values, _) = prove::<_, CpuProver<_, _>>(program, &stdin, config, SP1CoreOpts::default()).unwrap(); let mut public_values = SP1PublicValues::from(&public_values); @@ -197,7 +193,7 @@ mod test { let config = BabyBearPoseidon2::new(); let mut challenger = config.challenger(); let machine = RiscvAir::machine(config); - let (_, vk) = machine.setup(&Program::from(KECCAK256_ELF)); + let (_, vk) = machine.setup(&Program::from(KECCAK256_ELF).unwrap()); let _ = tracing::info_span!("verify").in_scope(|| machine.verify(&vk, &proof, &mut challenger)); diff --git a/core/src/syscall/precompiles/keccak256/columns.rs b/crates/core/machine/src/syscall/precompiles/keccak256/columns.rs similarity index 100% rename from core/src/syscall/precompiles/keccak256/columns.rs rename to crates/core/machine/src/syscall/precompiles/keccak256/columns.rs diff --git a/core/src/syscall/precompiles/keccak256/mod.rs b/crates/core/machine/src/syscall/precompiles/keccak256/mod.rs similarity index 56% rename from core/src/syscall/precompiles/keccak256/mod.rs rename to crates/core/machine/src/syscall/precompiles/keccak256/mod.rs index 5be4e52797..2f53e23c77 100644 --- a/core/src/syscall/precompiles/keccak256/mod.rs +++ b/crates/core/machine/src/syscall/precompiles/keccak256/mod.rs @@ -1,30 +1,13 @@ mod air; pub mod columns; -mod execute; mod trace; use p3_keccak_air::KeccakAir; -use serde::{Deserialize, Serialize}; - -use crate::runtime::{MemoryReadRecord, MemoryWriteRecord}; pub(crate) const STATE_SIZE: usize = 25; // The permutation state is 25 u64's. Our word size is 32 bits, so it is 50 words. -const STATE_NUM_WORDS: usize = STATE_SIZE * 2; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct KeccakPermuteEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub pre_state: [u64; STATE_SIZE], - pub post_state: [u64; STATE_SIZE], - pub state_read_records: Vec, - pub state_write_records: Vec, - pub state_addr: u32, -} +pub const STATE_NUM_WORDS: usize = STATE_SIZE * 2; pub struct KeccakPermuteChip { p3_keccak: KeccakAir, @@ -32,21 +15,16 @@ pub struct KeccakPermuteChip { impl KeccakPermuteChip { pub const fn new() -> Self { - Self { - p3_keccak: KeccakAir {}, - } + Self { p3_keccak: KeccakAir {} } } } #[cfg(test)] pub mod permute_tests { - use crate::runtime::SyscallCode; - use crate::stark::CpuProver; - use crate::utils::{run_test, SP1CoreOpts}; - use crate::{ - runtime::{Instruction, Opcode, Program, Runtime}, - utils::{self, tests::KECCAK_PERMUTE_ELF}, - }; + use sp1_core_executor::{syscalls::SyscallCode, Executor, Instruction, Opcode, Program}; + use sp1_stark::{CpuProver, SP1CoreOpts}; + + use crate::utils::{self, run_test, tests::KECCAK_PERMUTE_ELF}; pub fn keccak_permute_program() -> Program { let digest_ptr = 100; @@ -58,14 +36,7 @@ pub mod permute_tests { ]); } instructions.extend(vec![ - Instruction::new( - Opcode::ADD, - 5, - 0, - SyscallCode::KECCAK_PERMUTE as u32, - false, - true, - ), + Instruction::new(Opcode::ADD, 5, 0, SyscallCode::KECCAK_PERMUTE as u32, false, true), Instruction::new(Opcode::ADD, 10, 0, digest_ptr, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), ]); @@ -77,7 +48,7 @@ pub mod permute_tests { pub fn test_keccak_permute_program_execute() { utils::setup_logger(); let program = keccak_permute_program(); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); } @@ -92,7 +63,7 @@ pub mod permute_tests { #[test] fn test_keccak_permute_program_prove() { utils::setup_logger(); - let program = Program::from(KECCAK_PERMUTE_ELF); + let program = Program::from(KECCAK_PERMUTE_ELF).unwrap(); run_test::>(program).unwrap(); } } diff --git a/core/src/syscall/precompiles/keccak256/trace.rs b/crates/core/machine/src/syscall/precompiles/keccak256/trace.rs similarity index 97% rename from core/src/syscall/precompiles/keccak256/trace.rs rename to crates/core/machine/src/syscall/precompiles/keccak256/trace.rs index 3b9b973b92..bca7080734 100644 --- a/core/src/syscall/precompiles/keccak256/trace.rs +++ b/crates/core/machine/src/syscall/precompiles/keccak256/trace.rs @@ -2,19 +2,16 @@ use std::borrow::BorrowMut; use p3_field::PrimeField32; use p3_keccak_air::{generate_trace_rows, NUM_KECCAK_COLS, NUM_ROUNDS}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; - -use crate::bytes::event::ByteRecord; -use crate::{runtime::Program, stark::MachineRecord}; - -use crate::{air::MachineAir, runtime::ExecutionRecord}; +use sp1_core_executor::{ExecutionRecord, Program}; +use sp1_stark::{air::MachineAir, MachineRecord}; use super::{ columns::{KeccakMemCols, NUM_KECCAK_MEM_COLS}, KeccakPermuteChip, STATE_SIZE, }; +use sp1_core_executor::events::ByteRecord; impl MachineAir for KeccakPermuteChip { type Record = ExecutionRecord; diff --git a/crates/core/machine/src/syscall/precompiles/mod.rs b/crates/core/machine/src/syscall/precompiles/mod.rs new file mode 100644 index 0000000000..f07da94609 --- /dev/null +++ b/crates/core/machine/src/syscall/precompiles/mod.rs @@ -0,0 +1,6 @@ +pub mod edwards; +pub mod fptower; +pub mod keccak256; +pub mod sha256; +pub mod uint256; +pub mod weierstrass; diff --git a/core/src/syscall/precompiles/sha256/compress/air.rs b/crates/core/machine/src/syscall/precompiles/sha256/compress/air.rs similarity index 87% rename from core/src/syscall/precompiles/sha256/compress/air.rs rename to crates/core/machine/src/syscall/precompiles/sha256/compress/air.rs index 7a28a456b6..db1a58a7f0 100644 --- a/core/src/syscall/precompiles/sha256/compress/air.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/compress/air.rs @@ -3,16 +3,22 @@ use core::borrow::Borrow; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::AbstractField; use p3_matrix::Matrix; +use sp1_core_executor::syscalls::SyscallCode; +use sp1_stark::{air::SP1AirBuilder, Word}; -use super::columns::{ShaCompressCols, NUM_SHA_COMPRESS_COLS}; -use super::{ShaCompressChip, SHA_COMPRESS_K}; -use crate::air::{BaseAirBuilder, SP1AirBuilder, Word, WordAirBuilder}; -use crate::memory::MemoryCols; -use crate::operations::{ - Add5Operation, AddOperation, AndOperation, FixedRotateRightOperation, NotOperation, - XorOperation, +use super::{ + columns::{ShaCompressCols, NUM_SHA_COMPRESS_COLS}, + ShaCompressChip, SHA_COMPRESS_K, }; -use crate::runtime::SyscallCode; +use crate::{ + air::{MemoryAirBuilder, WordAirBuilder}, + memory::MemoryCols, + operations::{ + Add5Operation, AddOperation, AndOperation, FixedRotateRightOperation, NotOperation, + XorOperation, + }, +}; +use sp1_stark::air::BaseAirBuilder; impl BaseAir for ShaCompressChip { fn width(&self) -> usize { @@ -32,9 +38,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); self.eval_control_flow_flags(builder, local, next); @@ -44,10 +48,7 @@ where self.eval_finalize_ops(builder, local); - builder.assert_eq( - local.start, - local.is_real * local.octet[0] * local.octet_num[0], - ); + builder.assert_eq(local.start, local.is_real * local.octet[0] * local.octet_num[0]); builder.receive_syscall( local.shard, local.channel, @@ -85,10 +86,7 @@ impl ShaCompressChip { // Verify correct transition for octet column. for i in 0..8 { - builder - .when_transition() - .when(local.octet[i]) - .assert_one(next.octet[(i + 1) % 8]) + builder.when_transition().when(local.octet[i]).assert_one(next.octet[(i + 1) % 8]) } // Verify that all of the octet_num columns are bool. @@ -106,7 +104,8 @@ impl ShaCompressChip { // The first row should have octet_num[0] = 1 if it's real. builder.when_first_row().assert_one(local.octet_num[0]); - // If current row is not last of an octet and next row is real, octet_num should be the same. + // If current row is not last of an octet and next row is real, octet_num should be the + // same. for i in 0..10 { builder .when_transition() @@ -123,12 +122,8 @@ impl ShaCompressChip { } // Constrain A-H columns - let vars = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; - let next_vars = [ - next.a, next.b, next.c, next.d, next.e, next.f, next.g, next.h, - ]; + let vars = [local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h]; + let next_vars = [next.a, next.b, next.c, next.d, next.e, next.f, next.g, next.h]; for (i, var) in vars.iter().enumerate() { // For all initialize and finalize cycles, A-H should be the same in the next row. The // last cycle is an exception since the next row must be a new 80-cycle loop or nonreal. @@ -164,10 +159,7 @@ impl ShaCompressChip { // Assert that the is_finalize flag is correct. builder.assert_eq(local.is_finalize, local.octet_num[9] * local.is_real); - builder.assert_eq( - local.is_last_row.into(), - local.octet[7] * local.octet_num[9], - ); + builder.assert_eq(local.is_last_row.into(), local.octet[7] * local.octet_num[9]); // If this row is real and not the last cycle, then next row should have same inputs builder @@ -206,10 +198,7 @@ impl ShaCompressChip { .assert_one(next.is_real); // Once the is_real flag is changed to false, it should not be changed back. - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when_not(local.is_real).assert_zero(next.is_real); // Assert that the table ends in nonreal columns. Since each compress ecall is 80 cycles and // the table is padded to a power of 2, the last row of the table should always be padding. @@ -262,9 +251,7 @@ impl ShaCompressChip { // In the initialize phase, verify that local.a, local.b, ... is correctly read from memory // and does not change - let vars = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; + let vars = [local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h]; for (i, var) in vars.iter().enumerate() { builder .when(local.is_initialize) @@ -398,13 +385,7 @@ impl ShaCompressChip { // Calculate temp1 := h + S1 + ch + k[i] + w[i]. Add5Operation::::eval( builder, - &[ - local.h, - local.s1.value, - local.ch.value, - local.k, - local.mem.access.value, - ], + &[local.h, local.s1.value, local.ch.value, local.k, local.mem.access.value], local.shard, local.channel, local.is_compression, @@ -556,34 +537,16 @@ impl ShaCompressChip { // c := b // b := a // a := temp1 + temp2 - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.h, local.g); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.g, local.f); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.f, local.e); + builder.when_transition().when(local.is_compression).assert_word_eq(next.h, local.g); + builder.when_transition().when(local.is_compression).assert_word_eq(next.g, local.f); + builder.when_transition().when(local.is_compression).assert_word_eq(next.f, local.e); builder .when_transition() .when(local.is_compression) .assert_word_eq(next.e, local.d_add_temp1.value); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.d, local.c); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.c, local.b); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.b, local.a); + builder.when_transition().when(local.is_compression).assert_word_eq(next.d, local.c); + builder.when_transition().when(local.is_compression).assert_word_eq(next.c, local.b); + builder.when_transition().when(local.is_compression).assert_word_eq(next.b, local.a); builder .when_transition() .when(local.is_compression) @@ -599,9 +562,7 @@ impl ShaCompressChip { // phase's 8 rows. // We can get the needed operand (a,b,c,...,h) by doing an inner product between octet and // [a,b,c,...,h] which will act as a selector. - let add_operands = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; + let add_operands = [local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h]; let zero = AB::Expr::zero(); let mut filtered_operand = Word([zero.clone(), zero.clone(), zero.clone(), zero]); for (i, operand) in local.octet.iter().zip(add_operands.iter()) { diff --git a/core/src/syscall/precompiles/sha256/compress/columns.rs b/crates/core/machine/src/syscall/precompiles/sha256/compress/columns.rs similarity index 92% rename from core/src/syscall/precompiles/sha256/compress/columns.rs rename to crates/core/machine/src/syscall/precompiles/sha256/compress/columns.rs index 0fd7a7fbf4..d45b03ac7c 100644 --- a/core/src/syscall/precompiles/sha256/compress/columns.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/compress/columns.rs @@ -1,15 +1,15 @@ use std::mem::size_of; use sp1_derive::AlignedBorrow; - -use crate::air::Word; -use crate::memory::MemoryReadWriteCols; -use crate::operations::Add5Operation; -use crate::operations::AddOperation; -use crate::operations::AndOperation; -use crate::operations::FixedRotateRightOperation; -use crate::operations::NotOperation; -use crate::operations::XorOperation; +use sp1_stark::Word; + +use crate::{ + memory::MemoryReadWriteCols, + operations::{ + Add5Operation, AddOperation, AndOperation, FixedRotateRightOperation, NotOperation, + XorOperation, + }, +}; pub const NUM_SHA_COMPRESS_COLS: usize = size_of::>(); diff --git a/core/src/syscall/precompiles/sha256/compress/mod.rs b/crates/core/machine/src/syscall/precompiles/sha256/compress/mod.rs similarity index 74% rename from core/src/syscall/precompiles/sha256/compress/mod.rs rename to crates/core/machine/src/syscall/precompiles/sha256/compress/mod.rs index 5dbf5fdd29..539dbe885b 100644 --- a/core/src/syscall/precompiles/sha256/compress/mod.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/compress/mod.rs @@ -1,12 +1,7 @@ mod air; mod columns; -mod execute; mod trace; -use serde::{Deserialize, Serialize}; - -use crate::runtime::{MemoryReadRecord, MemoryWriteRecord}; - pub const SHA_COMPRESS_K: [u32; 64] = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, @@ -18,21 +13,6 @@ pub const SHA_COMPRESS_K: [u32; 64] = [ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ShaCompressEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub w_ptr: u32, - pub h_ptr: u32, - pub w: Vec, - pub h: [u32; 8], - pub h_read_records: [MemoryReadRecord; 8], - pub w_i_read_records: Vec, - pub h_write_records: [MemoryWriteRecord; 8], -} - /// Implements the SHA compress operation which loops over 0 = [0, 63] and modifies A-H in each /// iteration. The inputs to the syscall are a pointer to the 64 word array W and a pointer to the 8 /// word array H. @@ -52,11 +32,10 @@ impl ShaCompressChip { #[cfg(test)] pub mod compress_tests { - use crate::{ - runtime::{Instruction, Opcode, Program, SyscallCode}, - stark::CpuProver, - utils::{run_test, setup_logger, tests::SHA_COMPRESS_ELF}, - }; + use sp1_core_executor::{syscalls::SyscallCode, Instruction, Opcode, Program}; + use sp1_stark::CpuProver; + + use crate::utils::{run_test, setup_logger, tests::SHA_COMPRESS_ELF}; pub fn sha_compress_program() -> Program { let w_ptr = 100; @@ -75,14 +54,7 @@ pub mod compress_tests { ]); } instructions.extend(vec![ - Instruction::new( - Opcode::ADD, - 5, - 0, - SyscallCode::SHA_COMPRESS as u32, - false, - true, - ), + Instruction::new(Opcode::ADD, 5, 0, SyscallCode::SHA_COMPRESS as u32, false, true), Instruction::new(Opcode::ADD, 10, 0, w_ptr, false, true), Instruction::new(Opcode::ADD, 11, 0, h_ptr, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), @@ -100,7 +72,7 @@ pub mod compress_tests { #[test] fn test_sha_compress_program() { setup_logger(); - let program = Program::from(SHA_COMPRESS_ELF); + let program = Program::from(SHA_COMPRESS_ELF).unwrap(); run_test::>(program).unwrap(); } } diff --git a/core/src/syscall/precompiles/sha256/compress/trace.rs b/crates/core/machine/src/syscall/precompiles/sha256/compress/trace.rs similarity index 83% rename from core/src/syscall/precompiles/sha256/compress/trace.rs rename to crates/core/machine/src/syscall/precompiles/sha256/compress/trace.rs index d0f4a4da27..c8c0d910e1 100644 --- a/core/src/syscall/precompiles/sha256/compress/trace.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/compress/trace.rs @@ -3,20 +3,19 @@ use std::borrow::BorrowMut; use hashbrown::HashMap; use itertools::Itertools; use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, ShaCompressEvent}, + ExecutionRecord, Program, +}; +use sp1_stark::{air::MachineAir, Word}; use super::{ columns::{ShaCompressCols, NUM_SHA_COMPRESS_COLS}, - ShaCompressChip, ShaCompressEvent, SHA_COMPRESS_K, -}; -use crate::{ - air::{MachineAir, Word}, - bytes::{event::ByteRecord, ByteLookupEvent}, - runtime::{ExecutionRecord, Program}, - utils::pad_rows, + ShaCompressChip, SHA_COMPRESS_K, }; +use crate::utils::pad_rows; impl MachineAir for ShaCompressChip { type Record = ExecutionRecord; @@ -137,8 +136,7 @@ impl ShaCompressChip { cols.octet_num[octet_num_idx] = F::one(); cols.is_initialize = F::one(); - cols.mem - .populate_read(channel, event.h_read_records[j], blu); + cols.mem.populate_read(channel, event.h_read_records[j], blu); cols.mem_addr = F::from_canonical_u32(event.h_ptr + (j * 4) as u32); cols.a = Word::from(event.h_read_records[0].value); @@ -176,8 +174,7 @@ impl ShaCompressChip { cols.clk = F::from_canonical_u32(event.clk); cols.w_ptr = F::from_canonical_u32(event.w_ptr); cols.h_ptr = F::from_canonical_u32(event.h_ptr); - cols.mem - .populate_read(channel, event.w_i_read_records[j], blu); + cols.mem.populate_read(channel, event.w_i_read_records[j], blu); cols.mem_addr = F::from_canonical_u32(event.w_ptr + (j * 4) as u32); let a = h_array[0]; @@ -200,55 +197,36 @@ impl ShaCompressChip { let e_rr_6 = cols.e_rr_6.populate(blu, shard, channel, e, 6); let e_rr_11 = cols.e_rr_11.populate(blu, shard, channel, e, 11); let e_rr_25 = cols.e_rr_25.populate(blu, shard, channel, e, 25); - let s1_intermediate = cols - .s1_intermediate - .populate(blu, shard, channel, e_rr_6, e_rr_11); - let s1 = cols - .s1 - .populate(blu, shard, channel, s1_intermediate, e_rr_25); + let s1_intermediate = + cols.s1_intermediate.populate(blu, shard, channel, e_rr_6, e_rr_11); + let s1 = cols.s1.populate(blu, shard, channel, s1_intermediate, e_rr_25); let e_and_f = cols.e_and_f.populate(blu, shard, channel, e, f); let e_not = cols.e_not.populate(blu, shard, channel, e); let e_not_and_g = cols.e_not_and_g.populate(blu, shard, channel, e_not, g); let ch = cols.ch.populate(blu, shard, channel, e_and_f, e_not_and_g); - let temp1 = cols.temp1.populate( - blu, - shard, - channel, - h, - s1, - ch, - event.w[j], - SHA_COMPRESS_K[j], - ); + let temp1 = + cols.temp1.populate(blu, shard, channel, h, s1, ch, event.w[j], SHA_COMPRESS_K[j]); let a_rr_2 = cols.a_rr_2.populate(blu, shard, channel, a, 2); let a_rr_13 = cols.a_rr_13.populate(blu, shard, channel, a, 13); let a_rr_22 = cols.a_rr_22.populate(blu, shard, channel, a, 22); - let s0_intermediate = cols - .s0_intermediate - .populate(blu, shard, channel, a_rr_2, a_rr_13); - let s0 = cols - .s0 - .populate(blu, shard, channel, s0_intermediate, a_rr_22); + let s0_intermediate = + cols.s0_intermediate.populate(blu, shard, channel, a_rr_2, a_rr_13); + let s0 = cols.s0.populate(blu, shard, channel, s0_intermediate, a_rr_22); let a_and_b = cols.a_and_b.populate(blu, shard, channel, a, b); let a_and_c = cols.a_and_c.populate(blu, shard, channel, a, c); let b_and_c = cols.b_and_c.populate(blu, shard, channel, b, c); - let maj_intermediate = cols - .maj_intermediate - .populate(blu, shard, channel, a_and_b, a_and_c); - let maj = cols - .maj - .populate(blu, shard, channel, maj_intermediate, b_and_c); + let maj_intermediate = + cols.maj_intermediate.populate(blu, shard, channel, a_and_b, a_and_c); + let maj = cols.maj.populate(blu, shard, channel, maj_intermediate, b_and_c); let temp2 = cols.temp2.populate(blu, shard, channel, s0, maj); let d_add_temp1 = cols.d_add_temp1.populate(blu, shard, channel, d, temp1); - let temp1_add_temp2 = cols - .temp1_add_temp2 - .populate(blu, shard, channel, temp1, temp2); + let temp1_add_temp2 = cols.temp1_add_temp2.populate(blu, shard, channel, temp1, temp2); h_array[7] = g; h_array[6] = f; @@ -267,11 +245,7 @@ impl ShaCompressChip { } } - let mut v: [u32; 8] = (0..8) - .map(|i| h_array[i]) - .collect::>() - .try_into() - .unwrap(); + let mut v: [u32; 8] = (0..8).map(|i| h_array[i]).collect::>().try_into().unwrap(); octet_num_idx += 1; // Store a, b, c, d, e, f, g, h. @@ -289,10 +263,8 @@ impl ShaCompressChip { cols.octet_num[octet_num_idx] = F::one(); cols.is_finalize = F::one(); - cols.finalize_add - .populate(blu, shard, channel, og_h[j], h_array[j]); - cols.mem - .populate_write(channel, event.h_write_records[j], blu); + cols.finalize_add.populate(blu, shard, channel, og_h[j], h_array[j]); + cols.mem.populate_write(channel, event.h_write_records[j], blu); cols.mem_addr = F::from_canonical_u32(event.h_ptr + (j * 4) as u32); v[j] = h_array[j]; diff --git a/core/src/syscall/precompiles/sha256/extend/air.rs b/crates/core/machine/src/syscall/precompiles/sha256/extend/air.rs similarity index 95% rename from core/src/syscall/precompiles/sha256/extend/air.rs rename to crates/core/machine/src/syscall/precompiles/sha256/extend/air.rs index 69f38c3557..0344bf1b6c 100644 --- a/core/src/syscall/precompiles/sha256/extend/air.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/extend/air.rs @@ -1,15 +1,20 @@ use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::AbstractField; use p3_matrix::Matrix; +use sp1_core_executor::syscalls::SyscallCode; +use sp1_stark::air::SP1AirBuilder; use super::{ShaExtendChip, ShaExtendCols, NUM_SHA_EXTEND_COLS}; -use crate::air::{BaseAirBuilder, SP1AirBuilder}; -use crate::memory::MemoryCols; -use crate::operations::{ - Add4Operation, FixedRotateRightOperation, FixedShiftRightOperation, XorOperation, +use crate::{ + air::{MemoryAirBuilder, WordAirBuilder}, + memory::MemoryCols, + operations::{ + Add4Operation, FixedRotateRightOperation, FixedShiftRightOperation, XorOperation, + }, }; -use crate::runtime::SyscallCode; + use core::borrow::Borrow; +use sp1_stark::air::BaseAirBuilder; impl BaseAir for ShaExtendChip { fn width(&self) -> usize { @@ -30,9 +35,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let i_start = AB::F::from_canonical_u32(16); let nb_bytes_in_word = AB::F::from_canonical_u32(4); diff --git a/core/src/syscall/precompiles/sha256/extend/columns.rs b/crates/core/machine/src/syscall/precompiles/sha256/extend/columns.rs similarity index 88% rename from core/src/syscall/precompiles/sha256/extend/columns.rs rename to crates/core/machine/src/syscall/precompiles/sha256/extend/columns.rs index 0855b44139..2bb4f11afc 100644 --- a/core/src/syscall/precompiles/sha256/extend/columns.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/extend/columns.rs @@ -2,13 +2,13 @@ use std::mem::size_of; use sp1_derive::AlignedBorrow; -use crate::memory::MemoryReadCols; -use crate::memory::MemoryWriteCols; -use crate::operations::Add4Operation; -use crate::operations::FixedRotateRightOperation; -use crate::operations::FixedShiftRightOperation; -use crate::operations::IsZeroOperation; -use crate::operations::XorOperation; +use crate::{ + memory::{MemoryReadCols, MemoryWriteCols}, + operations::{ + Add4Operation, FixedRotateRightOperation, FixedShiftRightOperation, IsZeroOperation, + XorOperation, + }, +}; pub const NUM_SHA_EXTEND_COLS: usize = size_of::>(); diff --git a/core/src/syscall/precompiles/sha256/extend/flags.rs b/crates/core/machine/src/syscall/precompiles/sha256/extend/flags.rs similarity index 80% rename from core/src/syscall/precompiles/sha256/extend/flags.rs rename to crates/core/machine/src/syscall/precompiles/sha256/extend/flags.rs index a06f117e3d..dc26cf73d2 100644 --- a/core/src/syscall/precompiles/sha256/extend/flags.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/extend/flags.rs @@ -1,18 +1,13 @@ use core::borrow::Borrow; use p3_air::AirBuilder; use p3_baby_bear::BabyBear; -use p3_field::AbstractField; -use p3_field::Field; -use p3_field::PrimeField32; -use p3_field::TwoAdicField; +use p3_field::{AbstractField, Field, PrimeField32, TwoAdicField}; use p3_matrix::Matrix; +use sp1_stark::air::{BaseAirBuilder, SP1AirBuilder}; -use crate::air::BaseAirBuilder; -use crate::air::SP1AirBuilder; use crate::operations::IsZeroOperation; -use super::ShaExtendChip; -use super::ShaExtendCols; +use super::{ShaExtendChip, ShaExtendCols}; impl ShaExtendCols { pub fn populate_flags(&mut self, i: usize) { @@ -23,12 +18,10 @@ impl ShaExtendCols { self.cycle_16 = g.exp_u64((i + 1) as u64); // Populate the columns needed to track the start of a cycle of 16 rows. - self.cycle_16_start - .populate_from_field_element(self.cycle_16 - g); + self.cycle_16_start.populate_from_field_element(self.cycle_16 - g); // Populate the columns needed to track the end of a cycle of 16 rows. - self.cycle_16_end - .populate_from_field_element(self.cycle_16 - F::one()); + self.cycle_16_end.populate_from_field_element(self.cycle_16 - F::one()); // Populate the columns needed to keep track of cycles of 48 rows. let j = 16 + (i % 48); @@ -57,14 +50,10 @@ impl ShaExtendChip { builder.when_first_row().assert_eq(local.cycle_16, g); // First row of the table must have i = 16. - builder - .when_first_row() - .assert_eq(local.i, AB::F::from_canonical_u32(16)); + builder.when_first_row().assert_eq(local.i, AB::F::from_canonical_u32(16)); // Every row's `cycle_16` must be previous multiplied by `g`. - builder - .when_transition() - .assert_eq(local.cycle_16 * g, next.cycle_16); + builder.when_transition().assert_eq(local.cycle_16 * g, next.cycle_16); // Constrain `cycle_16_start.result` to be `cycle_16 - g == 0`. IsZeroOperation::::eval( @@ -83,17 +72,12 @@ impl ShaExtendChip { ); // Constrain `cycle_48` to be [1, 0, 0] in the first row. - builder - .when_first_row() - .assert_eq(local.cycle_48[0], AB::F::one()); - builder - .when_first_row() - .assert_eq(local.cycle_48[1], AB::F::zero()); - builder - .when_first_row() - .assert_eq(local.cycle_48[2], AB::F::zero()); + builder.when_first_row().assert_eq(local.cycle_48[0], AB::F::one()); + builder.when_first_row().assert_eq(local.cycle_48[1], AB::F::zero()); + builder.when_first_row().assert_eq(local.cycle_48[2], AB::F::zero()); - // Shift the indices of `cycles_48` at the end of each 16 rows. Otherwise, keep them the same. + // Shift the indices of `cycles_48` at the end of each 16 rows. Otherwise, keep them the + // same. for i in 0..3 { builder .when_transition() diff --git a/core/src/syscall/precompiles/sha256/extend/mod.rs b/crates/core/machine/src/syscall/precompiles/sha256/extend/mod.rs similarity index 69% rename from core/src/syscall/precompiles/sha256/extend/mod.rs rename to crates/core/machine/src/syscall/precompiles/sha256/extend/mod.rs index b3c365b256..998ef38663 100644 --- a/core/src/syscall/precompiles/sha256/extend/mod.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/extend/mod.rs @@ -1,28 +1,10 @@ mod air; mod columns; -mod execute; mod flags; mod trace; pub use columns::*; -use crate::runtime::{MemoryReadRecord, MemoryWriteRecord}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ShaExtendEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub w_ptr: u32, - pub w_i_minus_15_reads: Vec, - pub w_i_minus_2_reads: Vec, - pub w_i_minus_16_reads: Vec, - pub w_i_minus_7_reads: Vec, - pub w_i_writes: Vec, -} - /// Implements the SHA extension operation which loops over i = [16, 63] and modifies w[i] in each /// iteration. The only input to the syscall is the 4byte-aligned pointer to the w array. /// @@ -51,16 +33,14 @@ pub mod extend_tests { use p3_baby_bear::BabyBear; use p3_matrix::dense::RowMajorMatrix; + use sp1_core_executor::{ + events::AluEvent, syscalls::SyscallCode, ExecutionRecord, Instruction, Opcode, Program, + }; + use sp1_stark::{air::MachineAir, CpuProver}; - use crate::{ - air::MachineAir, - alu::AluEvent, - runtime::{ExecutionRecord, Instruction, Opcode, Program, SyscallCode}, - stark::CpuProver, - utils::{ - self, run_test, - tests::{SHA2_ELF, SHA_EXTEND_ELF}, - }, + use crate::utils::{ + self, run_test, + tests::{SHA2_ELF, SHA_EXTEND_ELF}, }; use super::ShaExtendChip; @@ -75,14 +55,7 @@ pub mod extend_tests { ]); } instructions.extend(vec![ - Instruction::new( - Opcode::ADD, - 5, - 0, - SyscallCode::SHA_EXTEND as u32, - false, - true, - ), + Instruction::new(Opcode::ADD, 5, 0, SyscallCode::SHA_EXTEND as u32, false, true), Instruction::new(Opcode::ADD, 10, 0, w_ptr, false, true), Instruction::new(Opcode::ADD, 11, 0, 0, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), @@ -110,14 +83,14 @@ pub mod extend_tests { #[test] fn test_sha256_program() { utils::setup_logger(); - let program = Program::from(SHA2_ELF); + let program = Program::from(SHA2_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_sha_extend_program() { utils::setup_logger(); - let program = Program::from(SHA_EXTEND_ELF); + let program = Program::from(SHA_EXTEND_ELF).unwrap(); run_test::>(program).unwrap(); } } diff --git a/core/src/syscall/precompiles/sha256/extend/trace.rs b/crates/core/machine/src/syscall/precompiles/sha256/extend/trace.rs similarity index 70% rename from core/src/syscall/precompiles/sha256/extend/trace.rs rename to crates/core/machine/src/syscall/precompiles/sha256/extend/trace.rs index d43f46ffbf..d38b32d85b 100644 --- a/core/src/syscall/precompiles/sha256/extend/trace.rs +++ b/crates/core/machine/src/syscall/precompiles/sha256/extend/trace.rs @@ -1,18 +1,16 @@ use hashbrown::HashMap; use itertools::Itertools; use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; -use std::borrow::BorrowMut; - -use crate::{ - air::MachineAir, - bytes::{event::ByteRecord, ByteLookupEvent}, - runtime::{ExecutionRecord, Program}, +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, ShaExtendEvent}, + ExecutionRecord, Program, }; +use sp1_stark::air::MachineAir; +use std::borrow::BorrowMut; -use super::{ShaExtendChip, ShaExtendCols, ShaExtendEvent, NUM_SHA_EXTEND_COLS}; +use super::{ShaExtendChip, ShaExtendCols, NUM_SHA_EXTEND_COLS}; impl MachineAir for ShaExtendChip { type Record = ExecutionRecord; @@ -110,26 +108,20 @@ impl ShaExtendChip { cols.clk = F::from_canonical_u32(event.clk); cols.w_ptr = F::from_canonical_u32(event.w_ptr); - cols.w_i_minus_15 - .populate(event.channel, event.w_i_minus_15_reads[j], blu); - cols.w_i_minus_2 - .populate(event.channel, event.w_i_minus_2_reads[j], blu); - cols.w_i_minus_16 - .populate(event.channel, event.w_i_minus_16_reads[j], blu); - cols.w_i_minus_7 - .populate(event.channel, event.w_i_minus_7_reads[j], blu); + cols.w_i_minus_15.populate(event.channel, event.w_i_minus_15_reads[j], blu); + cols.w_i_minus_2.populate(event.channel, event.w_i_minus_2_reads[j], blu); + cols.w_i_minus_16.populate(event.channel, event.w_i_minus_16_reads[j], blu); + cols.w_i_minus_7.populate(event.channel, event.w_i_minus_7_reads[j], blu); - // `s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)`. + // `s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift + // 3)`. let w_i_minus_15 = event.w_i_minus_15_reads[j].value; let w_i_minus_15_rr_7 = - cols.w_i_minus_15_rr_7 - .populate(blu, shard, event.channel, w_i_minus_15, 7); + cols.w_i_minus_15_rr_7.populate(blu, shard, event.channel, w_i_minus_15, 7); let w_i_minus_15_rr_18 = - cols.w_i_minus_15_rr_18 - .populate(blu, shard, event.channel, w_i_minus_15, 18); + cols.w_i_minus_15_rr_18.populate(blu, shard, event.channel, w_i_minus_15, 18); let w_i_minus_15_rs_3 = - cols.w_i_minus_15_rs_3 - .populate(blu, shard, event.channel, w_i_minus_15, 3); + cols.w_i_minus_15_rs_3.populate(blu, shard, event.channel, w_i_minus_15, 3); let s0_intermediate = cols.s0_intermediate.populate( blu, shard, @@ -137,25 +129,18 @@ impl ShaExtendChip { w_i_minus_15_rr_7, w_i_minus_15_rr_18, ); - let s0 = cols.s0.populate( - blu, - shard, - event.channel, - s0_intermediate, - w_i_minus_15_rs_3, - ); + let s0 = + cols.s0.populate(blu, shard, event.channel, s0_intermediate, w_i_minus_15_rs_3); - // `s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)`. + // `s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift + // 10)`. let w_i_minus_2 = event.w_i_minus_2_reads[j].value; let w_i_minus_2_rr_17 = - cols.w_i_minus_2_rr_17 - .populate(blu, shard, event.channel, w_i_minus_2, 17); + cols.w_i_minus_2_rr_17.populate(blu, shard, event.channel, w_i_minus_2, 17); let w_i_minus_2_rr_19 = - cols.w_i_minus_2_rr_19 - .populate(blu, shard, event.channel, w_i_minus_2, 19); + cols.w_i_minus_2_rr_19.populate(blu, shard, event.channel, w_i_minus_2, 19); let w_i_minus_2_rs_10 = - cols.w_i_minus_2_rs_10 - .populate(blu, shard, event.channel, w_i_minus_2, 10); + cols.w_i_minus_2_rs_10.populate(blu, shard, event.channel, w_i_minus_2, 10); let s1_intermediate = cols.s1_intermediate.populate( blu, shard, @@ -163,19 +148,13 @@ impl ShaExtendChip { w_i_minus_2_rr_17, w_i_minus_2_rr_19, ); - let s1 = cols.s1.populate( - blu, - shard, - event.channel, - s1_intermediate, - w_i_minus_2_rs_10, - ); + let s1 = + cols.s1.populate(blu, shard, event.channel, s1_intermediate, w_i_minus_2_rs_10); // Compute `s2`. let w_i_minus_7 = event.w_i_minus_7_reads[j].value; let w_i_minus_16 = event.w_i_minus_16_reads[j].value; - cols.s2 - .populate(blu, shard, event.channel, w_i_minus_16, s0, w_i_minus_7, s1); + cols.s2.populate(blu, shard, event.channel, w_i_minus_16, s0, w_i_minus_7, s1); cols.w_i.populate(event.channel, event.w_i_writes[j], blu); diff --git a/core/src/syscall/precompiles/sha256/mod.rs b/crates/core/machine/src/syscall/precompiles/sha256/mod.rs similarity index 100% rename from core/src/syscall/precompiles/sha256/mod.rs rename to crates/core/machine/src/syscall/precompiles/sha256/mod.rs diff --git a/core/src/syscall/precompiles/uint256/air.rs b/crates/core/machine/src/syscall/precompiles/uint256/air.rs similarity index 70% rename from core/src/syscall/precompiles/uint256/air.rs rename to crates/core/machine/src/syscall/precompiles/uint256/air.rs index 25477692c8..b0e77a6e51 100644 --- a/core/src/syscall/precompiles/uint256/air.rs +++ b/crates/core/machine/src/syscall/precompiles/uint256/air.rs @@ -1,53 +1,45 @@ -use crate::air::{BaseAirBuilder, MachineAir, Polynomial, SP1AirBuilder, WORD_SIZE}; -use crate::bytes::event::ByteRecord; -use crate::memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}; -use crate::operations::field::field_op::{FieldOpCols, FieldOperation}; -use crate::operations::field::params::NumWords; -use crate::operations::field::params::{Limbs, NumLimbs}; -use crate::operations::field::range::FieldLtCols; -use crate::operations::IsZeroOperation; -use crate::runtime::{ExecutionRecord, Program, Syscall, SyscallCode}; -use crate::runtime::{MemoryReadRecord, MemoryWriteRecord}; -use crate::stark::MachineRecord; -use crate::syscall::precompiles::SyscallContext; -use crate::utils::ec::uint256::U256Field; -use crate::utils::{ - bytes_to_words_le, limbs_from_access, limbs_from_prev_access, pad_rows, words_to_bytes_le, - words_to_bytes_le_vec, +use crate::{ + memory::{value_as_limbs, MemoryReadCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, }; + +use crate::{ + air::MemoryAirBuilder, + operations::{field::range::FieldLtCols, IsZeroOperation}, + utils::{ + limbs_from_access, limbs_from_prev_access, pad_rows, words_to_bytes_le, + words_to_bytes_le_vec, + }, +}; + use generic_array::GenericArray; use num::{BigUint, One, Zero}; -use p3_air::AirBuilder; -use p3_air::{Air, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use serde::{Deserialize, Serialize}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{Limbs, NumLimbs, NumWords}, + uint256::U256Field, +}; use sp1_derive::AlignedBorrow; -use std::borrow::{Borrow, BorrowMut}; -use std::mem::size_of; +use sp1_stark::{ + air::{BaseAirBuilder, MachineAir, Polynomial, SP1AirBuilder}, + MachineRecord, +}; +use std::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use typenum::Unsigned; /// The number of columns in the Uint256MulCols. const NUM_COLS: usize = size_of::>(); -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Uint256MulEvent { - pub lookup_id: u128, - pub shard: u32, - pub channel: u8, - pub clk: u32, - pub x_ptr: u32, - pub x: Vec, - pub y_ptr: u32, - pub y: Vec, - pub modulus: Vec, - pub x_memory_records: Vec, - pub y_memory_records: Vec, - pub modulus_memory_records: Vec, -} - #[derive(Default)] pub struct Uint256MulChip; @@ -88,7 +80,8 @@ pub struct Uint256MulCols { pub y_memory: GenericArray, WordsFieldElement>, pub modulus_memory: GenericArray, WordsFieldElement>, - /// Columns for checking if modulus is zero. If it's zero, then use 2^256 as the effective modulus. + /// Columns for checking if modulus is zero. If it's zero, then use 2^256 as the effective + /// modulus. pub modulus_is_zero: IsZeroOperation, /// Column that is equal to is_real * (1 - modulus_is_zero.result). @@ -167,11 +160,8 @@ impl MachineAir for Uint256MulChip { IsZeroOperation::populate(&mut cols.modulus_is_zero, modulus_byte_sum); // Populate the output column. - let effective_modulus = if modulus.is_zero() { - BigUint::one() << 256 - } else { - modulus.clone() - }; + let effective_modulus = + if modulus.is_zero() { BigUint::one() << 256 } else { modulus.clone() }; let result = cols.output.populate_with_modulus( &mut new_byte_lookup_events, event.shard, @@ -215,8 +205,7 @@ impl MachineAir for Uint256MulChip { let x = BigUint::zero(); let y = BigUint::zero(); - cols.output - .populate(&mut vec![], 0, 0, &x, &y, FieldOperation::Mul); + cols.output.populate(&mut vec![], 0, 0, &x, &y, FieldOperation::Mul); row }); @@ -240,80 +229,6 @@ impl MachineAir for Uint256MulChip { } } -impl Syscall for Uint256MulChip { - fn num_extra_cycles(&self) -> u32 { - 1 - } - - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let clk = rt.clk; - - let x_ptr = arg1; - if x_ptr % 4 != 0 { - panic!(); - } - let y_ptr = arg2; - if y_ptr % 4 != 0 { - panic!(); - } - - // First read the words for the x value. We can read a slice_unsafe here because we write - // the computed result to x later. - let x = rt.slice_unsafe(x_ptr, WORDS_FIELD_ELEMENT); - - // Read the y value. - let (y_memory_records, y) = rt.mr_slice(y_ptr, WORDS_FIELD_ELEMENT); - - // The modulus is stored after the y value. We increment the pointer by the number of words. - let modulus_ptr = y_ptr + WORDS_FIELD_ELEMENT as u32 * WORD_SIZE as u32; - let (modulus_memory_records, modulus) = rt.mr_slice(modulus_ptr, WORDS_FIELD_ELEMENT); - - // Get the BigUint values for x, y, and the modulus. - let uint256_x = BigUint::from_bytes_le(&words_to_bytes_le_vec(&x)); - let uint256_y = BigUint::from_bytes_le(&words_to_bytes_le_vec(&y)); - let uint256_modulus = BigUint::from_bytes_le(&words_to_bytes_le_vec(&modulus)); - - // Perform the multiplication and take the result modulo the modulus. - let result: BigUint = if uint256_modulus.is_zero() { - let modulus = BigUint::one() << 256; - (uint256_x * uint256_y) % modulus - } else { - (uint256_x * uint256_y) % uint256_modulus - }; - - let mut result_bytes = result.to_bytes_le(); - result_bytes.resize(32, 0u8); // Pad the result to 32 bytes. - - // Convert the result to little endian u32 words. - let result = bytes_to_words_le::<8>(&result_bytes); - - // Increment clk so that the write is not at the same cycle as the read. - rt.clk += 1; - // Write the result to x and keep track of the memory records. - let x_memory_records = rt.mw_slice(x_ptr, &result); - - let lookup_id = rt.syscall_lookup_id; - let shard = rt.current_shard(); - let channel = rt.current_channel(); - rt.record_mut().uint256_mul_events.push(Uint256MulEvent { - lookup_id, - shard, - channel, - clk, - x_ptr, - x, - y_ptr, - y, - modulus, - x_memory_records, - y_memory_records, - modulus_memory_records, - }); - - None - } -} - impl BaseAir for Uint256MulChip { fn width(&self) -> usize { NUM_COLS @@ -334,9 +249,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); // We are computing (x * y) % modulus. The value of x is stored in the "prev_value" of // the x_memory, since we write to it later. @@ -347,10 +260,8 @@ where // If the modulus is zero, then we don't perform the modulus operation. // Evaluate the modulus_is_zero operation by summing each byte of the modulus. The sum will // not overflow because we are summing 32 bytes. - let modulus_byte_sum = modulus_limbs - .0 - .iter() - .fold(AB::Expr::zero(), |acc, &limb| acc + limb); + let modulus_byte_sum = + modulus_limbs.0.iter().fold(AB::Expr::zero(), |acc, &limb| acc + limb); IsZeroOperation::::eval( builder, modulus_byte_sum, diff --git a/core/src/syscall/precompiles/uint256/mod.rs b/crates/core/machine/src/syscall/precompiles/uint256/mod.rs similarity index 53% rename from core/src/syscall/precompiles/uint256/mod.rs rename to crates/core/machine/src/syscall/precompiles/uint256/mod.rs index 69c740ef02..ce50c01cae 100644 --- a/core/src/syscall/precompiles/uint256/mod.rs +++ b/crates/core/machine/src/syscall/precompiles/uint256/mod.rs @@ -5,23 +5,19 @@ pub use air::*; #[cfg(test)] mod tests { - use crate::operations::field::params::FieldParameters; - use crate::stark::CpuProver; + use sp1_core_executor::Program; + use sp1_curves::{params::FieldParameters, uint256::U256Field, utils::biguint_from_limbs}; + use sp1_stark::CpuProver; + use crate::{ io::SP1Stdin, - runtime::Program, - utils::{ - self, - ec::{uint256::U256Field, utils::biguint_from_limbs}, - run_test_io, - tests::UINT256_MUL_ELF, - }, + utils::{self, run_test_io, tests::UINT256_MUL_ELF}, }; #[test] fn test_uint256_mul() { utils::setup_logger(); - let program = Program::from(UINT256_MUL_ELF); + let program = Program::from(UINT256_MUL_ELF).unwrap(); run_test_io::>(program, SP1Stdin::new()).unwrap(); } diff --git a/core/src/syscall/precompiles/weierstrass/mod.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/mod.rs similarity index 100% rename from core/src/syscall/precompiles/weierstrass/mod.rs rename to crates/core/machine/src/syscall/precompiles/weierstrass/mod.rs diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs similarity index 84% rename from core/src/syscall/precompiles/weierstrass/weierstrass_add.rs rename to crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs index 7574912035..40d82b9adb 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -1,42 +1,34 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; -use std::fmt::Debug; -use std::marker::PhantomData; - -use typenum::Unsigned; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; +use std::{fmt::Debug, marker::PhantomData}; +use crate::air::MemoryAirBuilder; use generic_array::GenericArray; -use num::BigUint; -use num::Zero; -use p3_air::AirBuilder; -use p3_air::{Air, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use num::{BigUint, Zero}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{FieldParameters, Limbs, NumLimbs, NumWords}, + weierstrass::WeierstrassParameters, + AffinePoint, CurveType, EllipticCurve, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{MachineAir, SP1AirBuilder}; +use typenum::Unsigned; -use crate::air::MachineAir; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::memory::MemoryCols; -use crate::memory::MemoryReadCols; -use crate::memory::MemoryWriteCols; -use crate::operations::field::field_op::FieldOpCols; -use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::{FieldParameters, Limbs, NumLimbs, NumWords}; -use crate::runtime::ExecutionRecord; -use crate::runtime::Program; -use crate::runtime::Syscall; -use crate::runtime::SyscallCode; -use crate::syscall::precompiles::create_ec_add_event; -use crate::syscall::precompiles::SyscallContext; -use crate::utils::ec::weierstrass::WeierstrassParameters; -use crate::utils::ec::AffinePoint; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurve; -use crate::utils::{limbs_from_prev_access, pad_rows}; +use crate::{ + memory::{MemoryCols, MemoryReadCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, + utils::{limbs_from_prev_access, pad_rows}, +}; pub const fn num_weierstrass_add_cols() -> usize { size_of::>() @@ -74,28 +66,9 @@ pub struct WeierstrassAddAssignChip { _marker: PhantomData, } -impl Syscall for WeierstrassAddAssignChip { - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let event = create_ec_add_event::(rt, arg1, arg2); - match E::CURVE_TYPE { - CurveType::Secp256k1 => rt.record_mut().secp256k1_add_events.push(event), - CurveType::Bn254 => rt.record_mut().bn254_add_events.push(event), - CurveType::Bls12381 => rt.record_mut().bls12381_add_events.push(event), - _ => panic!("Unsupported curve"), - } - None - } - - fn num_extra_cycles(&self) -> u32 { - 1 - } -} - impl WeierstrassAddAssignChip { pub const fn new() -> Self { - Self { - _marker: PhantomData, - } + Self { _marker: PhantomData } } #[allow(clippy::too_many_arguments)] @@ -350,9 +323,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let num_words_field_element = ::Limbs::USIZE / 4; @@ -488,7 +459,8 @@ where builder.eval_memory_access_slice( local.shard, local.channel, - local.clk + AB::F::from_canonical_u32(1), // We read p at +1 since p, q could be the same. + local.clk + AB::F::from_canonical_u32(1), /* We read p at +1 since p, q could be the + * same. */ local.p_ptr, &local.p_access, local.is_real, @@ -522,64 +494,63 @@ where #[cfg(test)] mod tests { - use crate::{ - runtime::Program, - stark::CpuProver, - utils::{ - run_test, setup_logger, - tests::{ - BLS12381_ADD_ELF, BLS12381_DOUBLE_ELF, BLS12381_MUL_ELF, BN254_ADD_ELF, - BN254_MUL_ELF, SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, - }, + use sp1_core_executor::Program; + use sp1_stark::CpuProver; + + use crate::utils::{ + run_test, setup_logger, + tests::{ + BLS12381_ADD_ELF, BLS12381_DOUBLE_ELF, BLS12381_MUL_ELF, BN254_ADD_ELF, BN254_MUL_ELF, + SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, }, }; #[test] fn test_secp256k1_add_simple() { setup_logger(); - let program = Program::from(SECP256K1_ADD_ELF); + let program = Program::from(SECP256K1_ADD_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bn254_add_simple() { setup_logger(); - let program = Program::from(BN254_ADD_ELF); + let program = Program::from(BN254_ADD_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bn254_mul_simple() { setup_logger(); - let program = Program::from(BN254_MUL_ELF); + let program = Program::from(BN254_MUL_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_secp256k1_mul_simple() { setup_logger(); - let program = Program::from(SECP256K1_MUL_ELF); + let program = Program::from(SECP256K1_MUL_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bls12381_add_simple() { setup_logger(); - let program = Program::from(BLS12381_ADD_ELF); + let program = Program::from(BLS12381_ADD_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bls12381_double_simple() { setup_logger(); - let program = Program::from(BLS12381_DOUBLE_ELF); + let program = Program::from(BLS12381_DOUBLE_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bls12381_mul_simple() { setup_logger(); - let program = Program::from(BLS12381_MUL_ELF); + let program = Program::from(BLS12381_MUL_ELF).unwrap(); run_test::>(program).unwrap(); } } diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs similarity index 82% rename from core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs rename to crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs index 85c4a5f89d..01fed80a01 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs @@ -1,42 +1,35 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use std::fmt::Debug; +use crate::air::MemoryAirBuilder; use generic_array::GenericArray; use num::{BigUint, Zero}; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_executor::{ + events::{ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{limbs_from_vec, FieldParameters, Limbs, NumLimbs, NumWords}, + weierstrass::{bls12_381::bls12381_sqrt, secp256k1::secp256k1_sqrt, WeierstrassParameters}, + CurveType, EllipticCurve, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir, SP1AirBuilder}; use std::marker::PhantomData; use typenum::Unsigned; -use crate::air::{BaseAirBuilder, MachineAir, SP1AirBuilder}; -use crate::bytes::event::ByteRecord; -use crate::memory::MemoryReadCols; -use crate::memory::MemoryReadWriteCols; -use crate::operations::field::field_op::FieldOpCols; -use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::field_sqrt::FieldSqrtCols; -use crate::operations::field::params::{limbs_from_vec, FieldParameters, NumWords}; -use crate::operations::field::params::{Limbs, NumLimbs}; -use crate::operations::field::range::FieldLtCols; -use crate::runtime::ExecutionRecord; -use crate::runtime::Program; -use crate::runtime::Syscall; -use crate::runtime::SyscallCode; -use crate::syscall::precompiles::create_ec_decompress_event; -use crate::syscall::precompiles::SyscallContext; -use crate::utils::ec::weierstrass::bls12_381::bls12381_sqrt; -use crate::utils::ec::weierstrass::secp256k1::secp256k1_sqrt; -use crate::utils::ec::weierstrass::WeierstrassParameters; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurve; -use crate::utils::limbs_from_access; -use crate::utils::limbs_from_prev_access; -use crate::utils::{bytes_to_words_le_vec, pad_rows}; +use crate::{ + memory::{MemoryReadCols, MemoryReadWriteCols}, + operations::field::{field_op::FieldOpCols, field_sqrt::FieldSqrtCols, range::FieldLtCols}, + utils::{bytes_to_words_le_vec, limbs_from_access, limbs_from_prev_access, pad_rows}, +}; pub const fn num_weierstrass_decompress_cols() -> usize { size_of::>() @@ -96,42 +89,17 @@ pub struct WeierstrassDecompressChip { _marker: PhantomData, } -impl Syscall for WeierstrassDecompressChip { - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let event = create_ec_decompress_event::(rt, arg1, arg2); - match E::CURVE_TYPE { - CurveType::Secp256k1 => rt.record_mut().k256_decompress_events.push(event), - CurveType::Bls12381 => rt.record_mut().bls12381_decompress_events.push(event), - _ => panic!("Unsupported curve"), - } - None - } - - fn num_extra_cycles(&self) -> u32 { - 0 - } -} - impl WeierstrassDecompressChip { pub const fn new(sign_rule: SignChoiceRule) -> Self { - Self { - sign_rule, - _marker: PhantomData::, - } + Self { sign_rule, _marker: PhantomData:: } } pub const fn with_lsb_rule() -> Self { - Self { - sign_rule: SignChoiceRule::LeastSignificantBit, - _marker: PhantomData::, - } + Self { sign_rule: SignChoiceRule::LeastSignificantBit, _marker: PhantomData:: } } pub const fn with_lexicographic_rule() -> Self { - Self { - sign_rule: SignChoiceRule::Lexicographic, - _marker: PhantomData::, - } + Self { sign_rule: SignChoiceRule::Lexicographic, _marker: PhantomData:: } } fn populate_field_ops( @@ -142,36 +110,23 @@ impl WeierstrassDecompressChip { x: BigUint, ) { // Y = sqrt(x^3 + b) - cols.range_x - .populate(record, shard, channel, &x, &E::BaseField::modulus()); - let x_2 = cols.x_2.populate( - record, - shard, - channel, - &x.clone(), - &x.clone(), - FieldOperation::Mul, - ); - let x_3 = cols - .x_3 - .populate(record, shard, channel, &x_2, &x, FieldOperation::Mul); + cols.range_x.populate(record, shard, channel, &x, &E::BaseField::modulus()); + let x_2 = + cols.x_2.populate(record, shard, channel, &x.clone(), &x.clone(), FieldOperation::Mul); + let x_3 = cols.x_3.populate(record, shard, channel, &x_2, &x, FieldOperation::Mul); let b = E::b_int(); let x_3_plus_b = - cols.x_3_plus_b - .populate(record, shard, channel, &x_3, &b, FieldOperation::Add); + cols.x_3_plus_b.populate(record, shard, channel, &x_3, &b, FieldOperation::Add); let sqrt_fn = match E::CURVE_TYPE { CurveType::Secp256k1 => secp256k1_sqrt, CurveType::Bls12381 => bls12381_sqrt, _ => panic!("Unsupported curve"), }; - let y = cols - .y - .populate(record, shard, channel, &x_3_plus_b, sqrt_fn); + let y = cols.y.populate(record, shard, channel, &x_3_plus_b, sqrt_fn); let zero = BigUint::zero(); - cols.neg_y - .populate(record, shard, channel, &zero, &y, FieldOperation::Sub); + cols.neg_y.populate(record, shard, channel, &zero, &y, FieldOperation::Sub); } } @@ -372,9 +327,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let num_limbs = ::Limbs::USIZE; let num_words_field_element = num_limbs / 4; @@ -513,12 +466,8 @@ where .assert_all_eq(local.neg_y.result, y_limbs); // Assert that the comparison only turns on when `is_real` is true. - builder - .when_not(local.is_real) - .assert_zero(choice_cols.when_sqrt_y_res_is_lt); - builder - .when_not(local.is_real) - .assert_zero(choice_cols.when_neg_y_res_is_lt); + builder.when_not(local.is_real).assert_zero(choice_cols.when_sqrt_y_res_is_lt); + builder.when_not(local.is_real).assert_zero(choice_cols.when_neg_y_res_is_lt); // Assert that the flags are set correctly. When the sign_bit is true, we want that // `neg_y < y`, and vice versa when the sign_bit is false. Hence, when should have: @@ -530,17 +479,14 @@ where // Since the when less-than flags are disjoint, we can assert that: // - When `sign_bit` is true , then is_y_eq_sqrt_y_result == when_neg_y_res_is_lt. // - When `sign_bit` is false, then is_y_eq_sqrt_y_result == when_sqrt_y_res_is_lt. - builder.when(local.is_real).when(local.sign_bit).assert_eq( - choice_cols.is_y_eq_sqrt_y_result, - choice_cols.when_neg_y_res_is_lt, - ); builder .when(local.is_real) - .when_not(local.sign_bit) - .assert_eq( - choice_cols.is_y_eq_sqrt_y_result, - choice_cols.when_sqrt_y_res_is_lt, - ); + .when(local.sign_bit) + .assert_eq(choice_cols.is_y_eq_sqrt_y_result, choice_cols.when_neg_y_res_is_lt); + builder.when(local.is_real).when_not(local.sign_bit).assert_eq( + choice_cols.is_y_eq_sqrt_y_result, + choice_cols.when_sqrt_y_res_is_lt, + ); // Assert the less-than comparisons according to the flags. @@ -610,18 +556,20 @@ where #[cfg(test)] mod tests { - use crate::io::SP1Stdin; - use crate::stark::CpuProver; - use crate::utils::{self, tests::BLS12381_DECOMPRESS_ELF}; - use crate::Program; - use amcl::bls381::bls381::basic::key_pair_generate_g2; - use amcl::bls381::bls381::utils::deserialize_g1; - use amcl::rand::RAND; + use crate::{ + io::SP1Stdin, + utils::{self, tests::BLS12381_DECOMPRESS_ELF}, + }; + use amcl::{ + bls381::bls381::{basic::key_pair_generate_g2, utils::deserialize_g1}, + rand::RAND, + }; use elliptic_curve::sec1::ToEncodedPoint; use rand::{thread_rng, Rng}; + use sp1_core_executor::Program; + use sp1_stark::CpuProver; - use crate::utils::run_test_io; - use crate::utils::tests::SECP256K1_DECOMPRESS_ELF; + use crate::utils::{run_test_io, tests::SECP256K1_DECOMPRESS_ELF}; #[test] fn test_weierstrass_bls_decompress() { @@ -638,9 +586,11 @@ mod tests { let (_, compressed) = key_pair_generate_g2(&mut rand); let stdin = SP1Stdin::from(&compressed); - let mut public_values = - run_test_io::>(Program::from(BLS12381_DECOMPRESS_ELF), stdin) - .unwrap(); + let mut public_values = run_test_io::>( + Program::from(BLS12381_DECOMPRESS_ELF).unwrap(), + stdin, + ) + .unwrap(); let mut result = [0; 96]; public_values.read_slice(&mut result); @@ -670,9 +620,11 @@ mod tests { let inputs = SP1Stdin::from(&compressed); - let mut public_values = - run_test_io::>(Program::from(SECP256K1_DECOMPRESS_ELF), inputs) - .unwrap(); + let mut public_values = run_test_io::>( + Program::from(SECP256K1_DECOMPRESS_ELF).unwrap(), + inputs, + ) + .unwrap(); let mut result = [0; 65]; public_values.read_slice(&mut result); assert_eq!(result, decompressed); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs similarity index 86% rename from core/src/syscall/precompiles/weierstrass/weierstrass_double.rs rename to crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 8e40405433..16dfe59264 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -1,43 +1,37 @@ -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; -use std::fmt::Debug; -use std::marker::PhantomData; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; +use std::{fmt::Debug, marker::PhantomData}; +use crate::air::MemoryAirBuilder; use generic_array::GenericArray; -use num::BigUint; -use num::Zero; -use p3_air::AirBuilder; -use p3_air::{Air, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSlice; +use num::{BigUint, Zero}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::{ParallelIterator, ParallelSlice}; +use sp1_core_executor::{ + events::{ByteLookupEvent, ByteRecord, FieldOperation}, + syscalls::SyscallCode, + ExecutionRecord, Program, +}; +use sp1_curves::{ + params::{FieldParameters, Limbs, NumLimbs, NumWords}, + weierstrass::WeierstrassParameters, + AffinePoint, CurveType, EllipticCurve, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::{ + air::{MachineAir, SP1AirBuilder}, + MachineRecord, +}; -use crate::air::MachineAir; -use crate::air::SP1AirBuilder; -use crate::bytes::event::ByteRecord; -use crate::bytes::ByteLookupEvent; -use crate::memory::MemoryCols; -use crate::memory::MemoryWriteCols; -use crate::operations::field::field_op::FieldOpCols; -use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::{FieldParameters, NumWords}; -use crate::operations::field::params::{Limbs, NumLimbs}; -use crate::runtime::ExecutionRecord; -use crate::runtime::Program; -use crate::runtime::Syscall; -use crate::runtime::SyscallCode; -use crate::stark::MachineRecord; -use crate::syscall::precompiles::create_ec_double_event; -use crate::syscall::precompiles::SyscallContext; -use crate::utils::ec::weierstrass::WeierstrassParameters; -use crate::utils::ec::AffinePoint; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurve; -use crate::utils::{limbs_from_prev_access, pad_rows}; +use crate::{ + memory::{MemoryCols, MemoryWriteCols}, + operations::field::field_op::FieldOpCols, + utils::{limbs_from_prev_access, pad_rows}, +}; pub const fn num_weierstrass_double_cols() -> usize { size_of::>() @@ -75,28 +69,9 @@ pub struct WeierstrassDoubleAssignChip { _marker: PhantomData, } -impl Syscall for WeierstrassDoubleAssignChip { - fn execute(&self, rt: &mut SyscallContext, arg1: u32, arg2: u32) -> Option { - let event = create_ec_double_event::(rt, arg1, arg2); - match E::CURVE_TYPE { - CurveType::Secp256k1 => rt.record_mut().secp256k1_double_events.push(event), - CurveType::Bn254 => rt.record_mut().bn254_double_events.push(event), - CurveType::Bls12381 => rt.record_mut().bls12381_double_events.push(event), - _ => panic!("Unsupported curve"), - } - None - } - - fn num_extra_cycles(&self) -> u32 { - 0 - } -} - impl WeierstrassDoubleAssignChip { pub const fn new() -> Self { - Self { - _marker: PhantomData, - } + Self { _marker: PhantomData } } fn populate_field_ops( @@ -365,9 +340,7 @@ where // Constrain the incrementing nonce. builder.when_first_row().assert_zero(local.nonce); - builder - .when_transition() - .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); let num_words_field_element = E::BaseField::NB_LIMBS / 4; let p_x = limbs_from_prev_access(&local.p_access[0..num_words_field_element]); @@ -547,33 +520,32 @@ where #[cfg(test)] pub mod tests { - use crate::{ - runtime::Program, - stark::CpuProver, - utils::{ - run_test, setup_logger, - tests::{BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF}, - }, + use sp1_core_executor::Program; + use sp1_stark::CpuProver; + + use crate::utils::{ + run_test, setup_logger, + tests::{BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF}, }; #[test] fn test_secp256k1_double_simple() { setup_logger(); - let program = Program::from(SECP256K1_DOUBLE_ELF); + let program = Program::from(SECP256K1_DOUBLE_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bn254_double_simple() { setup_logger(); - let program = Program::from(BN254_DOUBLE_ELF); + let program = Program::from(BN254_DOUBLE_ELF).unwrap(); run_test::>(program).unwrap(); } #[test] fn test_bls12381_double_simple() { setup_logger(); - let program = Program::from(BLS12381_DOUBLE_ELF); + let program = Program::from(BLS12381_DOUBLE_ELF).unwrap(); run_test::>(program).unwrap(); } } diff --git a/core/src/utils/buffer.rs b/crates/core/machine/src/utils/buffer.rs similarity index 90% rename from core/src/utils/buffer.rs rename to crates/core/machine/src/utils/buffer.rs index 3c15899c3a..96f8952cd3 100644 --- a/core/src/utils/buffer.rs +++ b/crates/core/machine/src/utils/buffer.rs @@ -10,17 +10,11 @@ pub struct Buffer { impl Buffer { pub const fn new() -> Self { - Self { - data: Vec::new(), - ptr: 0, - } + Self { data: Vec::new(), ptr: 0 } } pub fn from(data: &[u8]) -> Self { - Self { - data: data.to_vec(), - ptr: 0, - } + Self { data: data.to_vec(), ptr: 0 } } /// Set the position ptr to the beginning of the buffer. diff --git a/core/src/utils/concurrency.rs b/crates/core/machine/src/utils/concurrency.rs similarity index 86% rename from core/src/utils/concurrency.rs rename to crates/core/machine/src/utils/concurrency.rs index b5dec9024e..e095234fe5 100644 --- a/core/src/utils/concurrency.rs +++ b/crates/core/machine/src/utils/concurrency.rs @@ -9,10 +9,7 @@ pub struct TurnBasedSync { impl TurnBasedSync { /// Creates a new [TurnBasedSync]. pub fn new() -> Self { - TurnBasedSync { - current_turn: Mutex::new(0), - cv: Condvar::new(), - } + TurnBasedSync { current_turn: Mutex::new(0), cv: Condvar::new() } } /// Waits for the current turn to be equal to the given turn. diff --git a/core/src/utils/logger.rs b/crates/core/machine/src/utils/logger.rs similarity index 77% rename from core/src/utils/logger.rs rename to crates/core/machine/src/utils/logger.rs index a27cc34b75..c460a31628 100644 --- a/core/src/utils/logger.rs +++ b/crates/core/machine/src/utils/logger.rs @@ -1,10 +1,9 @@ use std::sync::Once; use tracing_forest::ForestLayer; -use tracing_subscriber::fmt::format::FmtSpan; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; -use tracing_subscriber::{EnvFilter, Registry}; +use tracing_subscriber::{ + fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry, +}; static INIT: Once = Once::new(); @@ -16,21 +15,19 @@ pub fn setup_logger() { let default_filter = "off"; let env_filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new(default_filter)) + .add_directive("hyper=off".parse().unwrap()) .add_directive("p3_keccak_air=off".parse().unwrap()) .add_directive("p3_fri=off".parse().unwrap()) .add_directive("p3_dft=off".parse().unwrap()) .add_directive("p3_challenger=off".parse().unwrap()); - // if the RUST_LOGGER environment variable is set, use it to determine which logger to configure - // (tracing_forest or tracing_subscriber) + // if the RUST_LOGGER environment variable is set, use it to determine which logger to + // configure (tracing_forest or tracing_subscriber) // otherwise, default to 'forest' let logger_type = std::env::var("RUST_LOGGER").unwrap_or_else(|_| "flat".to_string()); match logger_type.as_str() { "forest" => { - Registry::default() - .with(env_filter) - .with(ForestLayer::default()) - .init(); + Registry::default().with(env_filter).with(ForestLayer::default()).init(); } "flat" => { tracing_subscriber::fmt::Subscriber::builder() diff --git a/core/src/utils/mod.rs b/crates/core/machine/src/utils/mod.rs similarity index 77% rename from core/src/utils/mod.rs rename to crates/core/machine/src/utils/mod.rs index 2d8ff5c248..6c08a56569 100644 --- a/core/src/utils/mod.rs +++ b/crates/core/machine/src/utils/mod.rs @@ -1,27 +1,25 @@ mod buffer; pub mod concurrency; -mod config; -pub mod ec; mod logger; -mod options; #[cfg(any(test, feature = "programs"))] mod programs; mod prove; mod serde; +mod span; mod tracer; pub use buffer::*; -pub use config::*; pub use logger::*; -pub use options::*; pub use prove::*; pub use serde::*; +use sp1_curves::params::Limbs; +pub use span::*; pub use tracer::*; #[cfg(any(test, feature = "programs"))] pub use programs::*; -use crate::{memory::MemoryCols, operations::field::params::Limbs}; +use crate::memory::MemoryCols; use generic_array::ArrayLength; use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator}; @@ -47,26 +45,16 @@ pub fn pad_to_power_of_two(values: &mut Vec< pub fn limbs_from_prev_access>( cols: &[M], ) -> Limbs { - let vec = cols - .iter() - .flat_map(|access| access.prev_value().0) - .collect::>(); + let vec = cols.iter().flat_map(|access| access.prev_value().0).collect::>(); - let sized = vec - .try_into() - .unwrap_or_else(|_| panic!("failed to convert to limbs")); + let sized = vec.try_into().unwrap_or_else(|_| panic!("failed to convert to limbs")); Limbs(sized) } pub fn limbs_from_access>(cols: &[M]) -> Limbs { - let vec = cols - .iter() - .flat_map(|access| access.value().0) - .collect::>(); + let vec = cols.iter().flat_map(|access| access.value().0).collect::>(); - let sized = vec - .try_into() - .unwrap_or_else(|_| panic!("failed to convert to limbs")); + let sized = vec.try_into().unwrap_or_else(|_| panic!("failed to convert to limbs")); Limbs(sized) } @@ -107,10 +95,7 @@ pub fn next_power_of_two(n: usize, fixed_power: Option) -> usize { ); } if n > padded_nb_rows { - panic!( - "fixed log2 rows is too small: got {}, expected {}", - n, padded_nb_rows - ); + panic!("fixed log2 rows is too small: got {}, expected {}", n, padded_nb_rows); } padded_nb_rows } @@ -137,10 +122,7 @@ pub fn words_to_bytes_le(words: &[u32]) -> [u8; B] { /// Converts a slice of words to a byte vector in little endian. pub fn words_to_bytes_le_vec(words: &[u32]) -> Vec { - words - .iter() - .flat_map(|word| word.to_le_bytes().to_vec()) - .collect::>() + words.iter().flat_map(|word| word.to_le_bytes().to_vec()).collect::>() } /// Converts a byte array in little endian to a slice of words. @@ -207,16 +189,23 @@ where let ceil_div = (len + cpus - 1) / cpus; let chunk_size = std::cmp::max(ceil_div, cpus); - vec.chunks_mut(chunk_size * num_elements_per_event) - .enumerate() - .par_bridge() - .for_each(|(i, chunk)| { - chunk - .chunks_mut(num_elements_per_event) - .enumerate() - .for_each(|(j, row)| { - assert!(row.len() == num_elements_per_event); - processor(i * chunk_size + j, row); - }); - }); + vec.chunks_mut(chunk_size * num_elements_per_event).enumerate().par_bridge().for_each( + |(i, chunk)| { + chunk.chunks_mut(num_elements_per_event).enumerate().for_each(|(j, row)| { + assert!(row.len() == num_elements_per_event); + processor(i * chunk_size + j, row); + }); + }, + ); +} + +/// Returns whether the `SP1_DEBUG` environment variable is enabled or disabled. +/// +/// This variable controls whether backtraces are attached to compiled circuit programs, as well +/// as whether cycle tracking is performed for circuit programs. +/// +/// By default, the variable is disabled. +pub fn sp1_debug_mode() -> bool { + let value = std::env::var("SP1_DEBUG").unwrap_or_else(|_| "false".to_string()); + value == "1" || value.to_lowercase() == "true" } diff --git a/crates/core/machine/src/utils/programs.rs b/crates/core/machine/src/utils/programs.rs new file mode 100644 index 0000000000..5d51137dd3 --- /dev/null +++ b/crates/core/machine/src/utils/programs.rs @@ -0,0 +1,103 @@ +pub mod tests { + /// Demos. + + pub const CHESS_ELF: &[u8] = + include_bytes!("../../../../../examples/chess/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const FIBONACCI_IO_ELF: &[u8] = + include_bytes!("../../../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const IO_ELF: &[u8] = + include_bytes!("../../../../../examples/io/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const JSON_ELF: &[u8] = + include_bytes!("../../../../../examples/json/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const REGEX_ELF: &[u8] = + include_bytes!("../../../../../examples/regex/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const RSA_ELF: &[u8] = + include_bytes!("../../../../../examples/rsa/program/elf/riscv32im-succinct-zkvm-elf"); + + pub const SSZ_WITHDRAWALS_ELF: &[u8] = include_bytes!( + "../../../../../examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf" + ); + + pub const TENDERMINT_ELF: &[u8] = include_bytes!( + "../../../../../examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf" + ); + + /// Tests. + + pub const FIBONACCI_ELF: &[u8] = + include_bytes!("../../../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED25519_ELF: &[u8] = + include_bytes!("../../../../../tests/ed25519/elf/riscv32im-succinct-zkvm-elf"); + + pub const CYCLE_TRACKER_ELF: &[u8] = + include_bytes!("../../../../../tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED_ADD_ELF: &[u8] = + include_bytes!("../../../../../tests/ed-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const ED_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../../tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const KECCAK_PERMUTE_ELF: &[u8] = + include_bytes!("../../../../../tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf"); + + pub const KECCAK256_ELF: &[u8] = + include_bytes!("../../../../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_ADD_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA_COMPRESS_ELF: &[u8] = + include_bytes!("../../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA_EXTEND_ELF: &[u8] = + include_bytes!("../../../../../tests/sha-extend/elf/riscv32im-succinct-zkvm-elf"); + + pub const SHA2_ELF: &[u8] = + include_bytes!("../../../../../tests/sha2/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_ADD_ELF: &[u8] = + include_bytes!("../../../../../tests/bn254-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../../tests/bn254-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const BN254_MUL_ELF: &[u8] = + include_bytes!("../../../../../tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256K1_MUL_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_ADD_ELF: &[u8] = + include_bytes!("../../../../../tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../../tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_MUL_ELF: &[u8] = + include_bytes!("../../../../../tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const UINT256_MUL_ELF: &[u8] = + include_bytes!("../../../../../tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf"); + + pub const BLS12381_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../../tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const VERIFY_PROOF_ELF: &[u8] = + include_bytes!("../../../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); + + pub const PANIC_ELF: &[u8] = + include_bytes!("../../../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); +} diff --git a/core/src/utils/prove.rs b/crates/core/machine/src/utils/prove.rs similarity index 63% rename from core/src/utils/prove.rs rename to crates/core/machine/src/utils/prove.rs index e6e1ae3013..adedbd6065 100644 --- a/core/src/utils/prove.rs +++ b/crates/core/machine/src/utils/prove.rs @@ -1,48 +1,43 @@ -use std::collections::VecDeque; -use std::fs::File; -use std::io::Seek; -use std::io::{self}; -use std::sync::mpsc::sync_channel; -use std::sync::Arc; -use std::sync::Mutex; +use std::{ + collections::VecDeque, + fs::File, + io::{ + Seek, {self}, + }, + sync::{mpsc::sync_channel, Arc, Mutex}, +}; use web_time::Instant; +use crate::riscv::RiscvAir; use p3_challenger::CanObserve; use p3_maybe_rayon::prelude::*; -use serde::de::DeserializeOwned; -use serde::Serialize; +use serde::{de::DeserializeOwned, Serialize}; use size::Size; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, MachineVerificationError}; use std::thread::ScopedJoinHandle; use thiserror::Error; -pub use baby_bear_blake3::BabyBearBlake3; use p3_baby_bear::BabyBear; use p3_field::PrimeField32; -use crate::air::{MachineAir, PublicValues}; -use crate::io::{SP1PublicValues, SP1Stdin}; -use crate::lookup::InteractionBuilder; -use crate::runtime::{ExecutionError, NoOpSubproofVerifier, SP1Context}; -use crate::runtime::{ExecutionRecord, ExecutionReport}; -use crate::stark::DebugConstraintBuilder; -use crate::stark::MachineProof; -use crate::stark::MachineProver; -use crate::stark::ProverConstraintFolder; -use crate::stark::StarkVerifyingKey; -use crate::stark::Val; -use crate::stark::VerifierConstraintFolder; -use crate::stark::{Com, PcsProverData, RiscvAir, StarkProvingKey, UniConfig}; -use crate::stark::{MachineRecord, StarkMachine}; -use crate::utils::chunk_vec; -use crate::utils::concurrency::TurnBasedSync; -use crate::utils::SP1CoreOpts; +use crate::riscv::cost::CostEstimator; use crate::{ - runtime::{Program, Runtime}, - stark::StarkGenericConfig, - stark::{CpuProver, OpeningProof}, + io::{SP1PublicValues, SP1Stdin}, + utils::{chunk_vec, concurrency::TurnBasedSync}, }; +use sp1_core_executor::events::sorted_table_lines; -const LOG_DEGREE_BOUND: usize = 31; +use sp1_core_executor::{ + subproof::NoOpSubproofVerifier, ExecutionError, ExecutionRecord, ExecutionReport, Executor, + Program, SP1Context, +}; +use sp1_stark::{ + air::{MachineAir, PublicValues}, + Com, CpuProver, DebugConstraintBuilder, InteractionBuilder, MachineProof, MachineProver, + MachineRecord, OpeningProof, PcsProverData, ProverConstraintFolder, SP1CoreOpts, + StarkGenericConfig, StarkMachine, StarkProvingKey, StarkVerifyingKey, UniConfig, Val, + VerifierConstraintFolder, +}; #[derive(Error, Debug)] pub enum SP1CoreProverError { @@ -56,7 +51,7 @@ pub enum SP1CoreProverError { pub fn prove_simple>>( config: SC, - mut runtime: Runtime, + mut runtime: Executor, ) -> Result<(MachineProof, u64), SP1CoreProverError> where SC::Challenger: Clone, @@ -72,25 +67,15 @@ where let (pk, _) = prover.setup(runtime.program.as_ref()); // Set the shard numbers. - runtime - .records - .iter_mut() - .enumerate() - .for_each(|(i, shard)| { - shard.public_values.shard = (i + 1) as u32; - }); + runtime.records.iter_mut().enumerate().for_each(|(i, shard)| { + shard.public_values.shard = (i + 1) as u32; + }); // Prove the program. let mut challenger = prover.config().challenger(); let proving_start = Instant::now(); - let proof = prover - .prove( - &pk, - runtime.records, - &mut challenger, - SP1CoreOpts::default(), - ) - .unwrap(); + let proof = + prover.prove(&pk, runtime.records, &mut challenger, SP1CoreOpts::default()).unwrap(); let proving_duration = proving_start.elapsed().as_millis(); let nb_bytes = bincode::serialize(&proof).unwrap().len(); @@ -141,12 +126,15 @@ where PcsProverData: Send + Sync, { // Setup the runtime. - let mut runtime = Runtime::with_context(program.clone(), opts, context); + let mut runtime = Executor::with_context(program.clone(), opts, context); runtime.write_vecs(&stdin.buffer); for proof in stdin.proofs.iter() { runtime.write_proof(proof.0.clone(), proof.1.clone()); } + #[cfg(feature = "debug")] + let (all_records_tx, all_records_rx) = std::sync::mpsc::channel::>(); + // Record the start of the process. let proving_start = Instant::now(); let span = tracing::Span::current().clone(); @@ -168,9 +156,8 @@ where let _span = span.enter(); // Execute the runtime until we reach a checkpoint. - let (checkpoint, done) = runtime - .execute_state() - .map_err(SP1CoreProverError::ExecutionError)?; + let (checkpoint, done) = + runtime.execute_state().map_err(SP1CoreProverError::ExecutionError)?; // Save the checkpoint to a temp file. let mut checkpoint_file = @@ -197,10 +184,9 @@ where let p1_record_gen_sync = Arc::new(TurnBasedSync::new()); let p1_trace_gen_sync = Arc::new(TurnBasedSync::new()); let (p1_records_and_traces_tx, p1_records_and_traces_rx) = - sync_channel::<( - Vec, - Vec>)>>, - )>(opts.records_and_traces_channel_capacity); + sync_channel::<(Vec, Vec>)>>)>( + opts.records_and_traces_channel_capacity, + ); let p1_records_and_traces_tx = Arc::new(Mutex::new(p1_records_and_traces_tx)); let checkpoints_rx = Arc::new(Mutex::new(checkpoints_rx)); @@ -220,12 +206,17 @@ where let program = program.clone(); let span = tracing::Span::current().clone(); + + #[cfg(feature = "debug")] + let all_records_tx = all_records_tx.clone(); + let handle = s.spawn(move || { let _span = span.enter(); tracing::debug_span!("phase 1 trace generation").in_scope(|| { loop { // Receive the latest checkpoint. let received = { checkpoints_rx.lock().unwrap().recv() }; + if let Ok((index, mut checkpoint, done)) = received { // Trace the checkpoint and reconstruct the execution records. let (mut records, _) = tracing::debug_span!("trace checkpoint") @@ -291,6 +282,9 @@ where // Let another worker update the state. record_gen_sync.advance_turn(); + #[cfg(feature = "debug")] + all_records_tx.send(records.clone()).unwrap(); + // Generate the traces. let traces = records .par_iter() @@ -323,6 +317,8 @@ where p1_record_and_trace_gen_handles.push(handle); } drop(p1_records_and_traces_tx); + #[cfg(feature = "debug")] + drop(all_records_tx); // Create the challenger and observe the verifying key. let mut challenger = prover.config().challenger(); @@ -377,9 +373,7 @@ where let public_values_stream = checkpoint_generator_handle.join().unwrap().unwrap(); // Wait until the records and traces have been fully generated. - p1_record_and_trace_gen_handles - .into_iter() - .for_each(|handle| handle.join().unwrap()); + p1_record_and_trace_gen_handles.into_iter().for_each(|handle| handle.join().unwrap()); // Wait until the phase 1 prover has completely finished. let challenger = phase_1_prover_handle.join().unwrap(); @@ -388,10 +382,9 @@ where let p2_record_gen_sync = Arc::new(TurnBasedSync::new()); let p2_trace_gen_sync = Arc::new(TurnBasedSync::new()); let (p2_records_and_traces_tx, p2_records_and_traces_rx) = - sync_channel::<( - Vec, - Vec>)>>, - )>(opts.records_and_traces_channel_capacity); + sync_channel::<(Vec, Vec>)>>)>( + opts.records_and_traces_channel_capacity, + ); let p2_records_and_traces_tx = Arc::new(Mutex::new(p2_records_and_traces_tx)); let report_aggregate = Arc::new(Mutex::new(ExecutionReport::default())); @@ -535,9 +528,7 @@ where }); // Wait until the records and traces have been fully generated for phase 2. - p2_record_and_trace_gen_handles - .into_iter() - .for_each(|handle| handle.join().unwrap()); + p2_record_and_trace_gen_handles.into_iter().for_each(|handle| handle.join().unwrap()); // Wait until the phase 2 prover has finished. let shard_proofs = p2_prover_handle.join().unwrap(); @@ -545,19 +536,20 @@ where // Log some of the `ExecutionReport` information. let report_aggregate = report_aggregate.lock().unwrap(); tracing::info!( - "execution report (totals): total_cycles={}, total_syscall_cycles={}", + "execution report (totals): total_cycles={}, total_syscall_cycles={}, touched_memory_addresses={}", report_aggregate.total_instruction_count(), - report_aggregate.total_syscall_count() + report_aggregate.total_syscall_count(), + report_aggregate.touched_memory_addresses, ); - // Print the opcode and syscall count tables like `du`: sorted by count (descending) and with - // the count in the first column. + // Print the opcode and syscall count tables like `du`: sorted by count (descending) and + // with the count in the first column. tracing::info!("execution report (opcode counts):"); - for line in ExecutionReport::sorted_table_lines(&report_aggregate.opcode_counts) { + for line in sorted_table_lines(&report_aggregate.opcode_counts) { tracing::info!(" {line}"); } tracing::info!("execution report (syscall counts):"); - for line in ExecutionReport::sorted_table_lines(&report_aggregate.syscall_counts) { + for line in sorted_table_lines(&report_aggregate.syscall_counts) { tracing::info!(" {line}"); } @@ -567,13 +559,21 @@ where // Print the summary. let proving_time = proving_start.elapsed().as_secs_f64(); tracing::info!( - "summary: cycles={}, e2e={}s, khz={:.2}, proofSize={}", + "summary: cycles={}, gas={}, e2e={}s, khz={:.2}, proofSize={}", cycles, + report_aggregate.estimate_gas(), proving_time, (cycles as f64 / (proving_time * 1000.0) as f64), bincode::serialize(&proof).unwrap().len(), ); + #[cfg(feature = "debug")] + { + let all_records = all_records_rx.iter().flatten().collect::>(); + let mut challenger = prover.machine().config().challenger(); + prover.machine().debug_constraints(pk, all_records, &mut challenger); + } + Ok((proof, public_values_stream, cycles)) }) } @@ -582,9 +582,9 @@ where pub fn run_test_io>>( program: Program, inputs: SP1Stdin, -) -> Result> { +) -> Result> { let runtime = tracing::debug_span!("runtime.run(...)").in_scope(|| { - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.write_vecs(&inputs.buffer); runtime.run().unwrap(); runtime @@ -596,12 +596,9 @@ pub fn run_test_io>>( pub fn run_test>>( program: Program, -) -> Result< - crate::stark::MachineProof, - crate::stark::MachineVerificationError, -> { +) -> Result, MachineVerificationError> { let runtime = tracing::debug_span!("runtime.run(...)").in_scope(|| { - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.run().unwrap(); runtime }); @@ -610,12 +607,9 @@ pub fn run_test>>( #[allow(unused_variables)] pub fn run_test_core>>( - runtime: Runtime, + runtime: Executor, inputs: SP1Stdin, -) -> Result< - crate::stark::MachineProof, - crate::stark::MachineVerificationError, -> { +) -> Result, MachineVerificationError> { let config = BabyBearPoseidon2::new(); let machine = RiscvAir::machine(config); let prover = P::new(machine); @@ -640,15 +634,14 @@ pub fn run_test_core>>( } #[allow(unused_variables)] -pub fn run_test_machine( +pub fn run_test_machine_with_prover>( records: Vec, machine: StarkMachine, pk: StarkProvingKey, vk: StarkVerifyingKey, -) -> Result, crate::stark::MachineVerificationError> +) -> Result, MachineVerificationError> where A: MachineAir - + for<'a> Air> + Air>> + for<'a> Air> + for<'a> Air, SC::Challenge>>, @@ -660,13 +653,11 @@ where PcsProverData: Send + Sync + Serialize + DeserializeOwned, OpeningProof: Send + Sync, { - let start = Instant::now(); - let prover = CpuProver::new(machine); + let prover = P::new(machine); let mut challenger = prover.config().challenger(); - let proof = prover - .prove(&pk, records, &mut challenger, SP1CoreOpts::default()) - .unwrap(); - let time = start.elapsed().as_millis(); + let prove_span = tracing::debug_span!("prove").entered(); + let proof = prover.prove(&pk, records, &mut challenger, SP1CoreOpts::default()).unwrap(); + prove_span.exit(); let nb_bytes = bincode::serialize(&proof).unwrap().len(); let mut challenger = prover.config().challenger(); @@ -675,6 +666,30 @@ where Ok(proof) } +#[allow(unused_variables)] +pub fn run_test_machine( + records: Vec, + machine: StarkMachine, + pk: StarkProvingKey, + vk: StarkVerifyingKey, +) -> Result, MachineVerificationError> +where + A: MachineAir + + for<'a> Air> + + Air>> + + for<'a> Air> + + for<'a> Air, SC::Challenge>>, + A::Record: MachineRecord, + SC: StarkGenericConfig, + SC::Val: p3_field::PrimeField32, + SC::Challenger: Clone, + Com: Send + Sync, + PcsProverData: Send + Sync + Serialize + DeserializeOwned, + OpeningProof: Send + Sync, +{ + run_test_machine_with_prover::>(records, machine, pk, vk) +} + fn trace_checkpoint( program: Program, file: &File, @@ -682,7 +697,7 @@ fn trace_checkpoint( ) -> (Vec, ExecutionReport) { let mut reader = std::io::BufReader::new(file); let state = bincode::deserialize_from(&mut reader).expect("failed to deserialize state"); - let mut runtime = Runtime::recover(program.clone(), state, opts); + let mut runtime = Executor::recover(program.clone(), state, opts); // We already passed the deferred proof verifier when creating checkpoints, so the proofs were // already verified. So here we use a noop verifier to not print any warnings. runtime.subproof_verifier = Arc::new(NoOpSubproofVerifier); @@ -691,8 +706,7 @@ fn trace_checkpoint( } fn reset_seek(file: &mut File) { - file.seek(std::io::SeekFrom::Start(0)) - .expect("failed to seek to start of tempfile"); + file.seek(std::io::SeekFrom::Start(0)).expect("failed to seek to start of tempfile"); } #[cfg(debug_assertions)] @@ -759,423 +773,6 @@ where p3_uni_stark::verify(&UniConfig(config.clone()), air, challenger, proof, &vec![]) } -pub use baby_bear_keccak::BabyBearKeccak; -pub use baby_bear_poseidon2::BabyBearPoseidon2; use p3_air::Air; use p3_matrix::dense::RowMajorMatrix; use p3_uni_stark::Proof; - -pub mod baby_bear_poseidon2 { - - use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; - use p3_challenger::DuplexChallenger; - use p3_commit::ExtensionMmcs; - use p3_dft::Radix2DitParallel; - use p3_field::{extension::BinomialExtensionField, Field}; - use p3_fri::{FriConfig, TwoAdicFriPcs}; - use p3_merkle_tree::FieldMerkleTreeMmcs; - use p3_poseidon2::Poseidon2; - use p3_poseidon2::Poseidon2ExternalMatrixGeneral; - use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; - use serde::{Deserialize, Serialize}; - use sp1_primitives::RC_16_30; - - use crate::stark::StarkGenericConfig; - - pub type Val = BabyBear; - pub type Challenge = BinomialExtensionField; - - pub type Perm = Poseidon2; - pub type MyHash = PaddingFreeSponge; - pub type MyCompress = TruncatedPermutation; - pub type ValMmcs = FieldMerkleTreeMmcs< - ::Packing, - ::Packing, - MyHash, - MyCompress, - 8, - >; - pub type ChallengeMmcs = ExtensionMmcs; - pub type Dft = Radix2DitParallel; - pub type Challenger = DuplexChallenger; - type Pcs = TwoAdicFriPcs; - - pub fn my_perm() -> Perm { - const ROUNDS_F: usize = 8; - const ROUNDS_P: usize = 13; - let mut round_constants = RC_16_30.to_vec(); - let internal_start = ROUNDS_F / 2; - let internal_end = (ROUNDS_F / 2) + ROUNDS_P; - let internal_round_constants = round_constants - .drain(internal_start..internal_end) - .map(|vec| vec[0]) - .collect::>(); - let external_round_constants = round_constants; - Perm::new( - ROUNDS_F, - external_round_constants, - Poseidon2ExternalMatrixGeneral, - ROUNDS_P, - internal_round_constants, - DiffusionMatrixBabyBear, - ) - } - - pub fn default_fri_config() -> FriConfig { - let perm = my_perm(); - let hash = MyHash::new(perm.clone()); - let compress = MyCompress::new(perm.clone()); - let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress)); - let num_queries = match std::env::var("FRI_QUERIES") { - Ok(value) => value.parse().unwrap(), - Err(_) => 100, - }; - FriConfig { - log_blowup: 1, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - } - } - - pub fn compressed_fri_config() -> FriConfig { - let perm = my_perm(); - let hash = MyHash::new(perm.clone()); - let compress = MyCompress::new(perm.clone()); - let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress)); - let num_queries = match std::env::var("FRI_QUERIES") { - Ok(value) => value.parse().unwrap(), - Err(_) => 33, - }; - FriConfig { - log_blowup: 3, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - } - } - - enum BabyBearPoseidon2Type { - Default, - Compressed, - } - - #[derive(Deserialize)] - #[serde(from = "std::marker::PhantomData")] - pub struct BabyBearPoseidon2 { - pub perm: Perm, - pcs: Pcs, - config_type: BabyBearPoseidon2Type, - } - - impl BabyBearPoseidon2 { - pub fn new() -> Self { - let perm = my_perm(); - let hash = MyHash::new(perm.clone()); - let compress = MyCompress::new(perm.clone()); - let val_mmcs = ValMmcs::new(hash, compress); - let dft = Dft {}; - let fri_config = default_fri_config(); - let pcs = Pcs::new(27, dft, val_mmcs, fri_config); - Self { - pcs, - perm, - config_type: BabyBearPoseidon2Type::Default, - } - } - - pub fn compressed() -> Self { - let perm = my_perm(); - let hash = MyHash::new(perm.clone()); - let compress = MyCompress::new(perm.clone()); - let val_mmcs = ValMmcs::new(hash, compress); - let dft = Dft {}; - let fri_config = compressed_fri_config(); - let pcs = Pcs::new(27, dft, val_mmcs, fri_config); - Self { - pcs, - perm, - config_type: BabyBearPoseidon2Type::Compressed, - } - } - } - - impl Clone for BabyBearPoseidon2 { - fn clone(&self) -> Self { - match self.config_type { - BabyBearPoseidon2Type::Default => Self::new(), - BabyBearPoseidon2Type::Compressed => Self::compressed(), - } - } - } - - impl Default for BabyBearPoseidon2 { - fn default() -> Self { - Self::new() - } - } - - /// Implement serialization manually instead of using serde to avoid cloing the config. - impl Serialize for BabyBearPoseidon2 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - std::marker::PhantomData::.serialize(serializer) - } - } - - impl From> for BabyBearPoseidon2 { - fn from(_: std::marker::PhantomData) -> Self { - Self::new() - } - } - - impl StarkGenericConfig for BabyBearPoseidon2 { - type Val = BabyBear; - type Domain = >::Domain; - type Pcs = Pcs; - type Challenge = Challenge; - type Challenger = Challenger; - - fn pcs(&self) -> &Self::Pcs { - &self.pcs - } - - fn challenger(&self) -> Self::Challenger { - Challenger::new(self.perm.clone()) - } - } -} - -pub(super) mod baby_bear_keccak { - - use p3_baby_bear::BabyBear; - use p3_challenger::{HashChallenger, SerializingChallenger32}; - use p3_commit::ExtensionMmcs; - use p3_dft::Radix2DitParallel; - use p3_field::extension::BinomialExtensionField; - use p3_fri::{FriConfig, TwoAdicFriPcs}; - use p3_keccak::Keccak256Hash; - use p3_merkle_tree::FieldMerkleTreeMmcs; - use p3_symmetric::{CompressionFunctionFromHasher, SerializingHasher32}; - use serde::{Deserialize, Serialize}; - - use crate::stark::StarkGenericConfig; - - use super::LOG_DEGREE_BOUND; - - pub type Val = BabyBear; - - pub type Challenge = BinomialExtensionField; - - type ByteHash = Keccak256Hash; - type FieldHash = SerializingHasher32; - - type MyCompress = CompressionFunctionFromHasher; - - pub type ValMmcs = FieldMerkleTreeMmcs; - pub type ChallengeMmcs = ExtensionMmcs; - - pub type Dft = Radix2DitParallel; - - type Challenger = SerializingChallenger32>; - - type Pcs = TwoAdicFriPcs; - - #[derive(Deserialize)] - #[serde(from = "std::marker::PhantomData")] - pub struct BabyBearKeccak { - pcs: Pcs, - } - // Implement serialization manually instead of using serde(into) to avoid cloing the config - impl Serialize for BabyBearKeccak { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - std::marker::PhantomData::.serialize(serializer) - } - } - - impl From> for BabyBearKeccak { - fn from(_: std::marker::PhantomData) -> Self { - Self::new() - } - } - - impl BabyBearKeccak { - #[allow(dead_code)] - pub fn new() -> Self { - let byte_hash = ByteHash {}; - let field_hash = FieldHash::new(byte_hash); - - let compress = MyCompress::new(byte_hash); - - let val_mmcs = ValMmcs::new(field_hash, compress); - - let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone()); - - let dft = Dft {}; - - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 100, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - }; - let pcs = Pcs::new(LOG_DEGREE_BOUND, dft, val_mmcs, fri_config); - - Self { pcs } - } - } - - impl Default for BabyBearKeccak { - fn default() -> Self { - Self::new() - } - } - - impl Clone for BabyBearKeccak { - fn clone(&self) -> Self { - Self::new() - } - } - - impl StarkGenericConfig for BabyBearKeccak { - type Val = Val; - type Challenge = Challenge; - - type Domain = >::Domain; - - type Pcs = Pcs; - type Challenger = Challenger; - - fn pcs(&self) -> &Self::Pcs { - &self.pcs - } - - fn challenger(&self) -> Self::Challenger { - let byte_hash = ByteHash {}; - Challenger::from_hasher(vec![], byte_hash) - } - } -} - -pub(super) mod baby_bear_blake3 { - - use p3_baby_bear::BabyBear; - use p3_blake3::Blake3; - use p3_challenger::{HashChallenger, SerializingChallenger32}; - use p3_commit::ExtensionMmcs; - use p3_dft::Radix2DitParallel; - use p3_field::extension::BinomialExtensionField; - use p3_fri::{FriConfig, TwoAdicFriPcs}; - use p3_merkle_tree::FieldMerkleTreeMmcs; - use p3_symmetric::{CompressionFunctionFromHasher, SerializingHasher32}; - use serde::{Deserialize, Serialize}; - - use crate::stark::StarkGenericConfig; - - use super::LOG_DEGREE_BOUND; - - pub type Val = BabyBear; - - pub type Challenge = BinomialExtensionField; - - type ByteHash = Blake3; - type FieldHash = SerializingHasher32; - - type MyCompress = CompressionFunctionFromHasher; - - pub type ValMmcs = FieldMerkleTreeMmcs; - pub type ChallengeMmcs = ExtensionMmcs; - - pub type Dft = Radix2DitParallel; - - type Challenger = SerializingChallenger32>; - - type Pcs = TwoAdicFriPcs; - - #[derive(Deserialize)] - #[serde(from = "std::marker::PhantomData")] - pub struct BabyBearBlake3 { - pcs: Pcs, - } - - // Implement serialization manually instead of using serde(into) to avoid cloing the config - impl Serialize for BabyBearBlake3 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - std::marker::PhantomData::.serialize(serializer) - } - } - - impl From> for BabyBearBlake3 { - fn from(_: std::marker::PhantomData) -> Self { - Self::new() - } - } - - impl Clone for BabyBearBlake3 { - fn clone(&self) -> Self { - Self::new() - } - } - - impl BabyBearBlake3 { - pub fn new() -> Self { - let byte_hash = ByteHash {}; - let field_hash = FieldHash::new(byte_hash); - - let compress = MyCompress::new(byte_hash); - - let val_mmcs = ValMmcs::new(field_hash, compress); - - let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone()); - - let dft = Dft {}; - - let num_queries = match std::env::var("FRI_QUERIES") { - Ok(value) => value.parse().unwrap(), - Err(_) => 100, - }; - let fri_config = FriConfig { - log_blowup: 1, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - }; - let pcs = Pcs::new(LOG_DEGREE_BOUND, dft, val_mmcs, fri_config); - - Self { pcs } - } - } - - impl Default for BabyBearBlake3 { - fn default() -> Self { - Self::new() - } - } - - impl StarkGenericConfig for BabyBearBlake3 { - type Val = Val; - type Challenge = Challenge; - - type Domain = >::Domain; - - type Pcs = Pcs; - type Challenger = Challenger; - - fn pcs(&self) -> &Self::Pcs { - &self.pcs - } - - fn challenger(&self) -> Self::Challenger { - let byte_hash = ByteHash {}; - Challenger::from_hasher(vec![], byte_hash) - } - } -} diff --git a/core/src/utils/serde.rs b/crates/core/machine/src/utils/serde.rs similarity index 100% rename from core/src/utils/serde.rs rename to crates/core/machine/src/utils/serde.rs diff --git a/crates/core/machine/src/utils/span.rs b/crates/core/machine/src/utils/span.rs new file mode 100644 index 0000000000..032598cc26 --- /dev/null +++ b/crates/core/machine/src/utils/span.rs @@ -0,0 +1,130 @@ +use std::{collections::HashMap, fmt::Display, hash::Hash, iter::once}; + +use sp1_core_executor::events::sorted_table_lines; +use thiserror::Error; + +/// A builder to create a [`Span`]. +/// `S` is the type of span names and `T` is the type of item names. +#[derive(Debug, Clone)] +pub struct SpanBuilder { + pub parents: Vec>, + pub current_span: Span, +} + +impl SpanBuilder +where + S: Display, + T: Ord + Display + Hash, +{ + /// Create an empty builder with the given name for the root span. + pub fn new(name: S) -> Self { + Self { parents: Default::default(), current_span: Span::new(name) } + } + + /// Add an item to this span. + pub fn item(&mut self, item_name: impl Into) -> &mut Self + where + T: Hash + Eq, + { + self.current_span.cts.entry(item_name.into()).and_modify(|x| *x += 1).or_insert(1); + self + } + + /// Enter a new child span with the given name. + pub fn enter(&mut self, span_name: S) -> &mut Self { + let span = Span::new(span_name); + self.parents.push(core::mem::replace(&mut self.current_span, span)); + self + } + + /// Exit the current span, moving back to its parent. + /// + /// Yields an error if the current span is the root span, which may not be exited. + pub fn exit(&mut self) -> Result<&mut Self, SpanBuilderExitError> + where + T: Clone + Hash + Eq, + { + let mut parent_span = self.parents.pop().ok_or(SpanBuilderExitError::RootSpanExit)?; + // Add spanned instructions to parent. + for (instr_name, &ct) in self.current_span.cts.iter() { + // Always clones. Could be avoided with `raw_entry`, but it's not a big deal. + parent_span.cts.entry(instr_name.clone()).and_modify(|x| *x += ct).or_insert(ct); + } + // Move to the parent span. + let child_span = core::mem::replace(&mut self.current_span, parent_span); + self.current_span.children.push(child_span); + Ok(self) + } + + /// Get the root span, consuming the builder. + /// + /// Yields an error if the current span is not the root span. + pub fn finish(self) -> Result, SpanBuilderFinishError> { + if self.parents.is_empty() { + Ok(self.current_span) + } else { + Err(SpanBuilderFinishError::OpenSpan(self.current_span.name.to_string())) + } + } +} + +#[derive(Error, Debug, Clone)] +pub enum SpanBuilderError { + #[error(transparent)] + Exit(#[from] SpanBuilderExitError), + #[error(transparent)] + Finish(#[from] SpanBuilderFinishError), +} + +#[derive(Error, Debug, Clone)] +pub enum SpanBuilderExitError { + #[error("cannot exit root span")] + RootSpanExit, +} + +#[derive(Error, Debug, Clone)] +pub enum SpanBuilderFinishError { + #[error("open span: {0}")] + OpenSpan(String), +} + +/// A span for counting items in a recursive structure. Create and populate using [`SpanBuilder`]. +/// `S` is the type of span names and `T` is the type of item names. +#[derive(Debug, Clone, Default)] +pub struct Span { + pub name: S, + pub cts: HashMap, + pub children: Vec>, +} + +impl Span +where + S: Display, + T: Ord + Display + Hash, +{ + /// Create a new span with the given name. + pub fn new(name: S) -> Self { + Self { name, cts: Default::default(), children: Default::default() } + } + + /// Calculate the total number of items counted by this span and its children. + pub fn total(&self) -> usize { + self.cts.values().cloned().chain(self.children.iter().map(|x| x.total())).sum() + } + + /// Format and yield lines describing this span. Appropriate for logging. + pub fn lines(&self) -> Vec { + let Self { name, cts: instr_cts, children } = self; + + once(format!("{}", name)) + .chain( + children + .iter() + .flat_map(|c| c.lines()) + .chain(sorted_table_lines(instr_cts)) + .map(|line| format!("│ {line}")), + ) + .chain(once(format!("└╴ {} total", self.total()))) + .collect() + } +} diff --git a/core/src/utils/tracer.rs b/crates/core/machine/src/utils/tracer.rs similarity index 77% rename from core/src/utils/tracer.rs rename to crates/core/machine/src/utils/tracer.rs index 0ccfa94b64..88a4c7f6ac 100644 --- a/core/src/utils/tracer.rs +++ b/crates/core/machine/src/utils/tracer.rs @@ -2,9 +2,7 @@ use std::env; use tracing::level_filters::LevelFilter; use tracing_forest::ForestLayer; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; -use tracing_subscriber::{EnvFilter, Registry}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry}; /// A tracer to benchmark the performance of the vm. /// @@ -21,8 +19,5 @@ pub fn setup_tracer() { } else if tracer_config == "debug" { env_filter = env_filter.add_directive("sp1_core=debug".parse().unwrap()); } - Registry::default() - .with(env_filter) - .with(ForestLayer::default()) - .init(); + Registry::default().with(env_filter).with(ForestLayer::default()).init(); } diff --git a/server/CHANGELOG.md b/crates/cuda/CHANGELOG.md similarity index 84% rename from server/CHANGELOG.md rename to crates/cuda/CHANGELOG.md index 9d0e1d206c..742bfdced4 100644 --- a/server/CHANGELOG.md +++ b/crates/cuda/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), @@ -6,9 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-cuda-v1.2.0-rc1) - 2024-08-23 + +### Added + +- 1.2.0-rc1 cuda prover ([#1353](https://github.com/succinctlabs/sp1/pull/1353)) + +### Fixed + +- tokio block on ([#1346](https://github.com/succinctlabs/sp1/pull/1346)) + +### Other + +- merge dev into experimental pt 2 ([#1341](https://github.com/succinctlabs/sp1/pull/1341)) + ## [1.1.0](https://github.com/succinctlabs/sp1/releases/tag/sp1-server-v1.1.0) - 2024-08-02 ### Added + - experimental gpu support ([#1219](https://github.com/succinctlabs/sp1/pull/1219)) - update tg ([#1214](https://github.com/succinctlabs/sp1/pull/1214)) - v1.0.1 ([#1165](https://github.com/succinctlabs/sp1/pull/1165)) @@ -23,9 +39,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - tracing, profiling, benchmarking ([#99](https://github.com/succinctlabs/sp1/pull/99)) ### Fixed + - wait longer for server to start ([#1231](https://github.com/succinctlabs/sp1/pull/1231)) ### Other + - final touches for public release ([#239](https://github.com/succinctlabs/sp1/pull/239)) - update docs with slight nits ([#224](https://github.com/succinctlabs/sp1/pull/224)) - sp1 rename ([#212](https://github.com/succinctlabs/sp1/pull/212)) diff --git a/server/Cargo.toml b/crates/cuda/Cargo.toml similarity index 83% rename from server/Cargo.toml rename to crates/cuda/Cargo.toml index 88bc49b877..cb45ba910c 100644 --- a/server/Cargo.toml +++ b/crates/cuda/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "sp1-server" +name = "sp1-cuda" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +readme = "../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -10,8 +10,9 @@ keywords = { workspace = true } categories = { workspace = true } [dependencies] -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } sp1-prover = { workspace = true } +sp1-stark = { workspace = true } prost = "0.12" prost-types = "0.12" bincode = "1.3.3" @@ -28,7 +29,7 @@ prost-build = { version = "0.12", optional = true } twirp-build = { package = "twirp-build-rs", version = "0.3.0-succinct", optional = true } [dev-dependencies] -sp1-core = { workspace = true, features = ["programs"] } +sp1-core-machine = { workspace = true, features = ["programs"] } [features] default = [] diff --git a/server/build.rs b/crates/cuda/build.rs similarity index 100% rename from server/build.rs rename to crates/cuda/build.rs diff --git a/crates/cuda/proto/api.proto b/crates/cuda/proto/api.proto new file mode 100644 index 0000000000..c5e078676b --- /dev/null +++ b/crates/cuda/proto/api.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; + +package api; + +service ProverService { + rpc Ready(ReadyRequest) returns (ReadyResponse) {} + rpc ProveCore(ProveCoreRequest) returns (ProveCoreResponse) {} + rpc Compress(CompressRequest) returns (CompressResponse) {} + rpc Shrink(ShrinkRequest) returns (ShrinkResponse) {} + rpc Wrap(WrapRequest) returns (WrapResponse) {} +} + +message ReadyRequest {} + +message ReadyResponse { + bool ready = 1; +} + +message ProveCoreRequest { + bytes data = 1; +} + +message ProveCoreResponse { + bytes result = 1; +} + +message CompressRequest { + bytes data = 1; +} + +message CompressResponse { + bytes result = 1; +} + +message ShrinkRequest { + bytes data = 1; +} + +message ShrinkResponse { + bytes result = 1; +} + +message WrapRequest { + bytes data = 1; +} + +message WrapResponse { + bytes result = 1; +} \ No newline at end of file diff --git a/crates/cuda/src/lib.rs b/crates/cuda/src/lib.rs new file mode 100644 index 0000000000..06bf49b4a8 --- /dev/null +++ b/crates/cuda/src/lib.rs @@ -0,0 +1,369 @@ +#[rustfmt::skip] +pub mod proto { + pub mod api; +} + +use core::time::Duration; +use std::{ + future::Future, + io::{BufReader, Read, Write}, + process::{Command, Stdio}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; + +use crate::proto::api::ProverServiceClient; + +use proto::api::ReadyRequest; +use serde::{Deserialize, Serialize}; +use sp1_core_machine::{io::SP1Stdin, utils::SP1CoreProverError}; +use sp1_prover::{ + types::SP1ProvingKey, InnerSC, OuterSC, SP1CoreProof, SP1RecursionProverError, SP1ReduceProof, + SP1VerifyingKey, +}; +use sp1_stark::ShardProof; +use tokio::task::block_in_place; +use twirp::{url::Url, Client}; + +/// A remote client to [sp1_prover::SP1Prover] that runs inside a container. +/// +/// This is currently used to provide experimental support for GPU hardware acceleration. +/// +/// **WARNING**: This is an experimental feature and may not work as expected. +pub struct SP1CudaProver { + /// The gRPC client to communicate with the container. + client: Client, + /// The name of the container. + container_name: String, + /// A flag to indicate whether the container has already been cleaned up. + cleaned_up: Arc, +} + +/// The payload for the [sp1_prover::SP1Prover::prove_core] method. +/// +/// We use this object to serialize and deserialize the payload from the client to the server. +#[derive(Serialize, Deserialize)] +pub struct ProveCoreRequestPayload { + /// The proving key. + pub pk: SP1ProvingKey, + /// The input stream. + pub stdin: SP1Stdin, +} + +/// The payload for the [sp1_prover::SP1Prover::compress] method. +/// +/// We use this object to serialize and deserialize the payload from the client to the server. +#[derive(Serialize, Deserialize)] +pub struct CompressRequestPayload { + /// The verifying key. + pub vk: SP1VerifyingKey, + /// The core proof. + pub proof: SP1CoreProof, + /// The deferred proofs. + pub deferred_proofs: Vec>, +} + +/// The payload for the [sp1_prover::SP1Prover::shrink] method. +/// +/// We use this object to serialize and deserialize the payload from the client to the server. +#[derive(Serialize, Deserialize)] +pub struct ShrinkRequestPayload { + pub reduced_proof: SP1ReduceProof, +} + +/// The payload for the [sp1_prover::SP1Prover::wrap_bn254] method. +/// +/// We use this object to serialize and deserialize the payload from the client to the server. +#[derive(Serialize, Deserialize)] +pub struct WrapRequestPayload { + pub reduced_proof: SP1ReduceProof, +} + +impl SP1CudaProver { + /// Creates a new [SP1Prover] that runs inside a Docker container and returns a + /// [SP1ProverClient] that can be used to communicate with the container. + pub fn new() -> Self { + let container_name = "sp1-gpu"; + let image_name = "jtguibas/sp1-gpu:v1.2.0-rc1"; + + let cleaned_up = Arc::new(AtomicBool::new(false)); + let cleanup_name = container_name; + let cleanup_flag = cleaned_up.clone(); + + // Pull the docker image if it's not present. + Command::new("sudo") + .args(["docker", "pull", image_name]) + .output() + .expect("failed to pull docker image"); + + // Start the docker container. + let rust_log_level = std::env::var("RUST_LOG").unwrap_or("none".to_string()); + let mut child = Command::new("sudo") + .args([ + "docker", + "run", + "-e", + format!("RUST_LOG={}", rust_log_level).as_str(), + "-p", + "3000:3000", + "--rm", + "--runtime=nvidia", + "--gpus", + "all", + "--name", + container_name, + image_name, + ]) + .stdout(Stdio::piped()) + .spawn() + .expect("failed to start Docker container"); + + let stdout = child.stdout.take().unwrap(); + std::thread::spawn(move || { + let mut reader = BufReader::new(stdout); + let mut buffer = [0; 1024]; + loop { + match reader.read(&mut buffer) { + Ok(0) => break, + Ok(n) => { + std::io::stdout().write_all(&buffer[..n]).unwrap(); + std::io::stdout().flush().unwrap(); + } + Err(_) => break, + } + } + }); + + // Kill the container on control-c. + ctrlc::set_handler(move || { + tracing::debug!("received Ctrl+C, cleaning up..."); + if !cleanup_flag.load(Ordering::SeqCst) { + cleanup_container(cleanup_name); + cleanup_flag.store(true, Ordering::SeqCst); + } + std::process::exit(0); + }) + .unwrap(); + + // Wait a few seconds for the container to start. + std::thread::sleep(Duration::from_secs(2)); + + // Check if the container is ready. + let client = Client::from_base_url( + Url::parse("http://localhost:3000/twirp/").expect("failed to parse url"), + ) + .expect("failed to create client"); + block_on(async { + tracing::info!("waiting for proving server to be ready"); + loop { + let request = ReadyRequest {}; + let response = client.ready(request).await; + if let Ok(response) = response { + if response.ready { + tracing::info!("proving server is ready"); + break; + } + } + tracing::info!("proving server is not ready, retrying..."); + std::thread::sleep(Duration::from_secs(2)); + } + }); + + SP1CudaProver { + client: Client::from_base_url( + Url::parse("http://localhost:3000/twirp/").expect("failed to parse url"), + ) + .expect("failed to create client"), + container_name: container_name.to_string(), + cleaned_up: cleaned_up.clone(), + } + } + + /// Executes the [sp1_prover::SP1Prover::prove_core] method inside the container. + /// + /// You will need at least 24GB of VRAM to run this method. + /// + /// **WARNING**: This is an experimental feature and may not work as expected. + pub fn prove_core( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + ) -> Result { + let payload = ProveCoreRequestPayload { pk: pk.clone(), stdin: stdin.clone() }; + let request = + crate::proto::api::ProveCoreRequest { data: bincode::serialize(&payload).unwrap() }; + let response = block_on(async { self.client.prove_core(request).await }).unwrap(); + let proof: SP1CoreProof = bincode::deserialize(&response.result).unwrap(); + Ok(proof) + } + + /// Executes the [sp1_prover::SP1Prover::compress] method inside the container. + /// + /// You will need at least 24GB of VRAM to run this method. + /// + /// **WARNING**: This is an experimental feature and may not work as expected. + pub fn compress( + &self, + vk: &SP1VerifyingKey, + proof: SP1CoreProof, + deferred_proofs: Vec>, + ) -> Result, SP1RecursionProverError> { + let payload = CompressRequestPayload { vk: vk.clone(), proof, deferred_proofs }; + let request = + crate::proto::api::CompressRequest { data: bincode::serialize(&payload).unwrap() }; + + let response = block_on(async { self.client.compress(request).await }).unwrap(); + let proof: SP1ReduceProof = bincode::deserialize(&response.result).unwrap(); + Ok(proof) + } + + /// Executes the [sp1_prover::SP1Prover::shrink] method inside the container. + /// + /// You will need at least 40GB of VRAM to run this method. + /// + /// **WARNING**: This is an experimental feature and may not work as expected. + pub fn shrink( + &self, + reduced_proof: SP1ReduceProof, + ) -> Result, SP1RecursionProverError> { + let payload = ShrinkRequestPayload { reduced_proof: reduced_proof.clone() }; + let request = + crate::proto::api::ShrinkRequest { data: bincode::serialize(&payload).unwrap() }; + + let response = block_on(async { self.client.shrink(request).await }).unwrap(); + let proof: SP1ReduceProof = bincode::deserialize(&response.result).unwrap(); + Ok(proof) + } + + /// Executes the [sp1_prover::SP1Prover::wrap_bn254] method inside the container. + /// + /// You will need at least 40GB of VRAM to run this method. + /// + /// **WARNING**: This is an experimental feature and may not work as expected. + pub fn wrap_bn254( + &self, + reduced_proof: SP1ReduceProof, + ) -> Result, SP1RecursionProverError> { + let payload = WrapRequestPayload { reduced_proof: reduced_proof.clone() }; + let request = + crate::proto::api::WrapRequest { data: bincode::serialize(&payload).unwrap() }; + + let response = block_on(async { self.client.wrap(request).await }).unwrap(); + let proof: SP1ReduceProof = bincode::deserialize(&response.result).unwrap(); + Ok(proof) + } +} + +impl Default for SP1CudaProver { + fn default() -> Self { + Self::new() + } +} + +impl Drop for SP1CudaProver { + fn drop(&mut self) { + if !self.cleaned_up.load(Ordering::SeqCst) { + tracing::debug!("dropping SP1ProverClient, cleaning up..."); + cleanup_container(&self.container_name); + self.cleaned_up.store(true, Ordering::SeqCst); + } + } +} + +/// Cleans up the a docker container with the given name. +fn cleanup_container(container_name: &str) { + if let Err(e) = Command::new("sudo").args(["docker", "rm", "-f", container_name]).output() { + eprintln!("failed to remove container: {}", e); + } +} + +/// Utility method for blocking on an async function. +/// +/// If we're already in a tokio runtime, we'll block in place. Otherwise, we'll create a new +/// runtime. +pub fn block_on(fut: impl Future) -> T { + // Handle case if we're already in an tokio runtime. + if let Ok(handle) = tokio::runtime::Handle::try_current() { + block_in_place(|| handle.block_on(fut)) + } else { + // Otherwise create a new runtime. + let rt = tokio::runtime::Runtime::new().expect("Failed to create a new runtime"); + rt.block_on(fut) + } +} + +#[cfg(feature = "protobuf")] +#[cfg(test)] +mod tests { + use sp1_core_machine::utils::{setup_logger, tests::FIBONACCI_ELF}; + use sp1_prover::{ + components::DefaultProverComponents, InnerSC, SP1CoreProof, SP1Prover, SP1ReduceProof, + }; + use twirp::{url::Url, Client}; + + use crate::{ + proto::api::ProverServiceClient, CompressRequestPayload, ProveCoreRequestPayload, + SP1CudaProver, SP1Stdin, + }; + + #[test] + fn test_client() { + setup_logger(); + + let prover = SP1Prover::::new(); + let client = SP1CudaProver::new(); + let (pk, vk) = prover.setup(FIBONACCI_ELF); + + println!("proving core"); + let proof = client.prove_core(&pk, &SP1Stdin::new()).unwrap(); + + println!("verifying core"); + prover.verify(&proof.proof, &vk).unwrap(); + + println!("proving compress"); + let proof = client.compress(&vk, proof, vec![]).unwrap(); + + println!("verifying compress"); + prover.verify_compressed(&proof, &vk).unwrap(); + + println!("proving shrink"); + let proof = client.shrink(proof).unwrap(); + + println!("verifying shrink"); + prover.verify_shrink(&proof, &vk).unwrap(); + + println!("proving wrap_bn254"); + let proof = client.wrap_bn254(proof).unwrap(); + + println!("verifying wrap_bn254"); + prover.verify_wrap_bn254(&proof, &vk).unwrap(); + } + + #[tokio::test] + async fn test_prove_core() { + let client = + Client::from_base_url(Url::parse("http://localhost:3000/twirp/").unwrap()).unwrap(); + + let prover = SP1Prover::::new(); + let (pk, vk) = prover.setup(FIBONACCI_ELF); + let payload = ProveCoreRequestPayload { pk, stdin: SP1Stdin::new() }; + let request = + crate::proto::api::ProveCoreRequest { data: bincode::serialize(&payload).unwrap() }; + let proof = client.prove_core(request).await.unwrap(); + let proof: SP1CoreProof = bincode::deserialize(&proof.result).unwrap(); + prover.verify(&proof.proof, &vk).unwrap(); + + tracing::info!("compress"); + let payload = CompressRequestPayload { vk: vk.clone(), proof, deferred_proofs: vec![] }; + let request = + crate::proto::api::CompressRequest { data: bincode::serialize(&payload).unwrap() }; + let compressed_proof = client.compress(request).await.unwrap(); + let compressed_proof: SP1ReduceProof = + bincode::deserialize(&compressed_proof.result).unwrap(); + + tracing::info!("verify compressed"); + prover.verify_compressed(&compressed_proof, &vk).unwrap(); + } +} diff --git a/crates/cuda/src/proto/api.rs b/crates/cuda/src/proto/api.rs new file mode 100644 index 0000000000..f36b4e4da5 --- /dev/null +++ b/crates/cuda/src/proto/api.rs @@ -0,0 +1,190 @@ +// This file is @generated by prost-build. +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReadyRequest {} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReadyResponse { + #[prost(bool, tag = "1")] + pub ready: bool, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProveCoreRequest { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProveCoreResponse { + #[prost(bytes = "vec", tag = "1")] + pub result: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CompressRequest { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CompressResponse { + #[prost(bytes = "vec", tag = "1")] + pub result: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ShrinkRequest { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ShrinkResponse { + #[prost(bytes = "vec", tag = "1")] + pub result: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct WrapRequest { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct WrapResponse { + #[prost(bytes = "vec", tag = "1")] + pub result: ::prost::alloc::vec::Vec, +} +pub use twirp; +pub const SERVICE_FQN: &str = "/api.ProverService"; +#[twirp::async_trait::async_trait] +pub trait ProverService { + async fn ready( + &self, + ctx: twirp::Context, + req: ReadyRequest, + ) -> Result; + async fn prove_core( + &self, + ctx: twirp::Context, + req: ProveCoreRequest, + ) -> Result; + async fn compress( + &self, + ctx: twirp::Context, + req: CompressRequest, + ) -> Result; + async fn shrink( + &self, + ctx: twirp::Context, + req: ShrinkRequest, + ) -> Result; + async fn wrap( + &self, + ctx: twirp::Context, + req: WrapRequest, + ) -> Result; +} +pub fn router(api: std::sync::Arc) -> twirp::Router +where + T: ProverService + Send + Sync + 'static, +{ + twirp::details::TwirpRouterBuilder::new(api) + .route( + "/Ready", + |api: std::sync::Arc, ctx: twirp::Context, req: ReadyRequest| async move { + api.ready(ctx, req).await + }, + ) + .route( + "/ProveCore", + |api: std::sync::Arc, ctx: twirp::Context, req: ProveCoreRequest| async move { + api.prove_core(ctx, req).await + }, + ) + .route( + "/Compress", + |api: std::sync::Arc, ctx: twirp::Context, req: CompressRequest| async move { + api.compress(ctx, req).await + }, + ) + .route( + "/Shrink", + |api: std::sync::Arc, ctx: twirp::Context, req: ShrinkRequest| async move { + api.shrink(ctx, req).await + }, + ) + .route( + "/Wrap", + |api: std::sync::Arc, ctx: twirp::Context, req: WrapRequest| async move { + api.wrap(ctx, req).await + }, + ) + .build() +} +#[twirp::async_trait::async_trait] +pub trait ProverServiceClient: Send + Sync + std::fmt::Debug { + async fn ready( + &self, + req: ReadyRequest, + ) -> Result; + async fn prove_core( + &self, + req: ProveCoreRequest, + ) -> Result; + async fn compress( + &self, + req: CompressRequest, + ) -> Result; + async fn shrink( + &self, + req: ShrinkRequest, + ) -> Result; + async fn wrap(&self, req: WrapRequest) -> Result; +} +#[twirp::async_trait::async_trait] +impl ProverServiceClient for twirp::client::Client { + async fn ready( + &self, + req: ReadyRequest, + ) -> Result { + let url = self.base_url.join("api.ProverService/Ready")?; + self.request(url, req).await + } + async fn prove_core( + &self, + req: ProveCoreRequest, + ) -> Result { + let url = self.base_url.join("api.ProverService/ProveCore")?; + self.request(url, req).await + } + async fn compress( + &self, + req: CompressRequest, + ) -> Result { + let url = self.base_url.join("api.ProverService/Compress")?; + self.request(url, req).await + } + async fn shrink( + &self, + req: ShrinkRequest, + ) -> Result { + let url = self.base_url.join("api.ProverService/Shrink")?; + self.request(url, req).await + } + async fn wrap(&self, req: WrapRequest) -> Result { + let url = self.base_url.join("api.ProverService/Wrap")?; + self.request(url, req).await + } +} diff --git a/crates/curves/CHANGELOG.md b/crates/curves/CHANGELOG.md new file mode 100644 index 0000000000..ec13c87c90 --- /dev/null +++ b/crates/curves/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-curves-v1.2.0-rc1) - 2024-08-23 + +### Other + +- runtime optimizations ([#1344](https://github.com/succinctlabs/sp1/pull/1344)) +- resolve merge conflicts between dev and experimental +- refactor + cleanup core crates diff --git a/crates/curves/Cargo.toml b/crates/curves/Cargo.toml new file mode 100644 index 0000000000..85e468f7b7 --- /dev/null +++ b/crates/curves/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "sp1-curves" +description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." +readme = "../../README.md" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } + +[dependencies] +num = "0.4.3" +serde = { version = "1.0.207", features = ["derive"] } +typenum = "1.17.0" +curve25519-dalek = { version = "4.1.2" } +k256 = { version = "0.13.3", features = ["expose-field"] } +generic-array = { version = "1.1.0", features = ["alloc", "serde"] } +amcl = { package = "snowbridge-amcl", version = "1.0.2", default-features = false, features = [ + "bls381", +] } +elliptic-curve = "0.13.8" +dashu = "0.4.2" + +sp1-stark = { workspace = true } + +sp1-primitives = { workspace = true } +p3-field = { workspace = true } +itertools = "0.13.0" + +[dev-dependencies] +rand = "0.8.5" diff --git a/core/src/utils/ec/edwards/ed25519.rs b/crates/curves/src/edwards/ed25519.rs similarity index 91% rename from core/src/utils/ec/edwards/ed25519.rs rename to crates/curves/src/edwards/ed25519.rs index 435e9985f2..c2a823c603 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/crates/curves/src/edwards/ed25519.rs @@ -6,9 +6,11 @@ use num::{BigUint, Num, One}; use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; -use crate::operations::field::params::{FieldParameters, NumLimbs}; -use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; -use crate::utils::ec::{AffinePoint, CurveType, EllipticCurveParameters}; +use crate::{ + edwards::{EdwardsCurve, EdwardsParameters}, + params::{FieldParameters, NumLimbs}, + AffinePoint, CurveType, EllipticCurveParameters, +}; pub type Ed25519 = EdwardsCurve; @@ -72,7 +74,8 @@ impl EdwardsParameters for Ed25519Parameters { /// significant bit of the result is always 0. pub fn ed25519_sqrt(a: &BigUint) -> BigUint { // Here is a description of how to calculate sqrt in the Curve25519 base field: - // ssh://git@github.com/succinctlabs/curve25519-dalek/blob/e2d1bd10d6d772af07cac5c8161cd7655016af6d/curve25519-dalek/src/field.rs#L256 + // ssh://git@github.com/succinctlabs/curve25519-dalek/blob/ + // e2d1bd10d6d772af07cac5c8161cd7655016af6d/curve25519-dalek/src/field.rs#L256 let modulus = Ed25519BaseField::modulus(); // The exponent is (modulus+3)/8; @@ -86,7 +89,9 @@ pub fn ed25519_sqrt(a: &BigUint) -> BigUint { // The square root of -1 in the field. // Take from here: - // ssh://git@github.com/succinctlabs/curve25519-dalek/blob/e2d1bd10d6d772af07cac5c8161cd7655016af6d/curve25519-dalek/src/backend/serial/u64/constants.rs#L89 + // ssh://git@github.com/succinctlabs/curve25519-dalek/blob/ + // e2d1bd10d6d772af07cac5c8161cd7655016af6d/curve25519-dalek/src/backend/serial/u64/constants. + // rs#L89 let sqrt_m1 = BigUint::from_str( "19681161376707505956807079304988542015446066515923890162744021073123829784752", ) diff --git a/core/src/utils/ec/edwards/mod.rs b/crates/curves/src/edwards/mod.rs similarity index 86% rename from core/src/utils/ec/edwards/mod.rs rename to crates/curves/src/edwards/mod.rs index 30639bbf70..1344dff6bc 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/crates/curves/src/edwards/mod.rs @@ -5,8 +5,23 @@ use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; use super::CurveType; -use crate::operations::field::params::{FieldParameters, NumLimbs}; -use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; +use crate::{ + params::{FieldParameters, NumLimbs}, + AffinePoint, EllipticCurve, EllipticCurveParameters, +}; + +use crate::{edwards::ed25519::Ed25519BaseField, params::NumWords}; +use typenum::Unsigned; + +pub type Limbs = ::Limbs; +pub const NUM_LIMBS: usize = Limbs::USIZE; + +pub type WordsFieldElement = ::WordsFieldElement; +pub const WORDS_FIELD_ELEMENT: usize = WordsFieldElement::USIZE; + +#[allow(unused)] +pub type WordsCurvePoint = ::WordsCurvePoint; +pub const WORDS_CURVE_POINT: usize = WordsCurvePoint::USIZE; pub trait EdwardsParameters: EllipticCurveParameters { const D: GenericArray::Limbs>; @@ -125,7 +140,7 @@ mod tests { use rand::thread_rng; use super::*; - use crate::utils::ec::edwards::ed25519::{Ed25519, Ed25519Parameters}; + use crate::edwards::ed25519::{Ed25519, Ed25519Parameters}; #[test] fn test_bigint_ed_add() { diff --git a/core/src/utils/ec/mod.rs b/crates/curves/src/lib.rs similarity index 86% rename from core/src/utils/ec/mod.rs rename to crates/curves/src/lib.rs index 1d96f58c3c..7b91ab429f 100644 --- a/core/src/utils/ec/mod.rs +++ b/crates/curves/src/lib.rs @@ -1,19 +1,33 @@ pub mod edwards; +pub mod params; +// pub mod polynomial; pub mod scalar_mul; pub mod uint256; pub mod utils; pub mod weierstrass; -use std::fmt::{Debug, Display, Formatter, Result}; -use std::ops::{Add, Neg}; +pub mod curve25519_dalek { + pub use curve25519_dalek::edwards::CompressedEdwardsY; +} + +pub mod k256 { + pub use k256::{ + ecdsa::{RecoveryId, Signature, VerifyingKey}, + elliptic_curve::ops::Invert, + }; +} + +use params::{FieldParameters, NumWords}; +use sp1_primitives::consts::WORD_SIZE; +use std::{ + fmt::{Debug, Display, Formatter, Result}, + ops::{Add, Neg}, +}; use typenum::Unsigned; use num::BigUint; use serde::{de::DeserializeOwned, Serialize}; -use crate::air::WORD_SIZE; -use crate::operations::field::params::{FieldParameters, NumWords}; - pub const NUM_WORDS_FIELD_ELEMENT: usize = 8; pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_SIZE; pub const COMPRESSED_POINT_BYTES: usize = 32; @@ -51,29 +65,17 @@ pub struct AffinePoint { impl AffinePoint { #[allow(dead_code)] pub const fn new(x: BigUint, y: BigUint) -> Self { - Self { - x, - y, - _marker: std::marker::PhantomData, - } + Self { x, y, _marker: std::marker::PhantomData } } pub fn from_words_le(words: &[u32]) -> Self { - let x_bytes = words[0..words.len() / 2] - .iter() - .flat_map(|n| n.to_le_bytes()) - .collect::>(); - let y_bytes = &words[words.len() / 2..] - .iter() - .flat_map(|n| n.to_le_bytes()) - .collect::>(); + let x_bytes = + words[0..words.len() / 2].iter().flat_map(|n| n.to_le_bytes()).collect::>(); + let y_bytes = + &words[words.len() / 2..].iter().flat_map(|n| n.to_le_bytes()).collect::>(); let x = BigUint::from_bytes_le(x_bytes.as_slice()); let y = BigUint::from_bytes_le(y_bytes.as_slice()); - Self { - x, - y, - _marker: std::marker::PhantomData, - } + Self { x, y, _marker: std::marker::PhantomData } } pub fn to_words_le(&self) -> Vec { diff --git a/crates/curves/src/params.rs b/crates/curves/src/params.rs new file mode 100644 index 0000000000..7bf2af5459 --- /dev/null +++ b/crates/curves/src/params.rs @@ -0,0 +1,166 @@ +use std::{ + fmt::Debug, + ops::{Div, Index, IndexMut}, + slice::Iter, +}; + +use serde::{de::DeserializeOwned, Serialize}; + +use typenum::{Unsigned, U2, U4}; + +use generic_array::{sequence::GenericSequence, ArrayLength, GenericArray}; +use num::BigUint; +use sp1_stark::air::Polynomial; + +use p3_field::Field; + +use crate::utils::biguint_from_limbs; + +pub const NB_BITS_PER_LIMB: usize = 8; + +/// An array representing N limbs of T. +/// +/// GenericArray allows us to constrain the correct array lengths so we can have # of limbs and # of +/// witness limbs associated in NumLimbs / FieldParameters. +/// See: https://github.com/RustCrypto/traits/issues/1481 +#[derive(Debug, Clone)] +pub struct Limbs(pub GenericArray); + +pub trait FieldParameters: + Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + NumLimbs +{ + const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; + const NB_LIMBS: usize = Self::Limbs::USIZE; + const NB_WITNESS_LIMBS: usize = Self::Witness::USIZE; + const WITNESS_OFFSET: usize; + + /// The bytes of the modulus in little-endian order. + const MODULUS: &'static [u8]; + + fn modulus() -> BigUint { + biguint_from_limbs(Self::MODULUS) + } + + fn nb_bits() -> usize { + Self::NB_BITS_PER_LIMB * Self::NB_LIMBS + } + + fn modulus_field_iter() -> impl Iterator { + Self::MODULUS.iter().map(|x| F::from_canonical_u8(*x)).take(Self::NB_LIMBS) + } + + /// Convert a BigUint to a Vec of u8 limbs (with len NB_LIMBS). + fn to_limbs(x: &BigUint) -> Vec { + let mut bytes = x.to_bytes_le(); + bytes.resize(Self::NB_LIMBS, 0u8); + bytes + } + + /// Convert a BigUint to a Vec of F limbs (with len NB_LIMBS). + fn to_limbs_field_vec, F: Field>(x: &BigUint) -> Vec { + Self::to_limbs(x).into_iter().map(|x| F::from_canonical_u8(x).into()).collect::>() + } + + /// Convert a BigUint to Limbs. + fn to_limbs_field, F: Field>(x: &BigUint) -> Limbs { + limbs_from_vec(Self::to_limbs_field_vec(x)) + } +} + +/// Convert a vec of F limbs to a Limbs of N length. +pub fn limbs_from_vec, N: ArrayLength, F: Field>(limbs: Vec) -> Limbs { + debug_assert_eq!(limbs.len(), N::USIZE); + let mut result = GenericArray::::generate(|_i| F::zero().into()); + for (i, limb) in limbs.into_iter().enumerate() { + result[i] = limb.into(); + } + Limbs(result) +} + +/// Trait that holds the typenum values for # of limbs and # of witness limbs. +pub trait NumLimbs: Clone + Debug { + type Limbs: ArrayLength + Debug; + type Witness: ArrayLength + Debug; +} + +/// Trait that holds number of words needed to represent a field element and a curve point. +pub trait NumWords: Clone + Debug { + /// The number of words needed to represent a field element. + type WordsFieldElement: ArrayLength + Debug; + /// The number of words needed to represent a curve point (two field elements). + type WordsCurvePoint: ArrayLength + Debug; +} + +/// Implement NumWords for NumLimbs where # Limbs is divisible by 4. +/// +/// Using typenum we can do N/4 and N/2 in type-level arithmetic. Having it as a separate trait +/// avoids needing the Div where clauses everywhere. +impl NumWords for N +where + N::Limbs: Div, + N::Limbs: Div, + >::Output: ArrayLength + Debug, + >::Output: ArrayLength + Debug, +{ + /// Each word has 4 limbs so we divide by 4. + type WordsFieldElement = >::Output; + /// Curve point has 2 field elements so we divide by 2. + type WordsCurvePoint = >::Output; +} + +impl Copy for Limbs where N::ArrayType: Copy {} + +impl Default for Limbs +where + T: Default + Copy, +{ + fn default() -> Self { + Self(GenericArray::default()) + } +} + +impl Index for Limbs { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for Limbs { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +impl IntoIterator for Limbs { + type Item = T; + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl + Clone, N: ArrayLength, Expr: Clone> From> + for Polynomial +{ + fn from(value: Limbs) -> Self { + Polynomial::from_coefficients(&value.0.into_iter().map(|x| x.into()).collect::>()) + } +} + +impl From> for Limbs { + fn from(value: Polynomial) -> Self { + let inner = value.as_coefficients().try_into().unwrap(); + Self(inner) + } +} + +impl<'a, T: Debug + Default + Clone, N: ArrayLength> From> for Limbs { + fn from(value: Iter<'a, T>) -> Self { + let vec: Vec = value.cloned().collect(); + let inner = vec.try_into().unwrap(); + Self(inner) + } +} diff --git a/core/src/air/polynomial.rs b/crates/curves/src/polynomial.rs similarity index 100% rename from core/src/air/polynomial.rs rename to crates/curves/src/polynomial.rs diff --git a/core/src/utils/ec/scalar_mul.rs b/crates/curves/src/scalar_mul.rs similarity index 93% rename from core/src/utils/ec/scalar_mul.rs rename to crates/curves/src/scalar_mul.rs index 098b11fc51..ea8dd58a73 100644 --- a/core/src/utils/ec/scalar_mul.rs +++ b/crates/curves/src/scalar_mul.rs @@ -2,9 +2,7 @@ use core::ops::Mul; use num::{BigUint, One}; -use super::utils::biguint_to_bits_le; -use super::AffinePoint; -use super::EllipticCurve; +use super::{utils::biguint_to_bits_le, AffinePoint, EllipticCurve}; impl AffinePoint { pub fn scalar_mul(&self, scalar: &BigUint) -> Self { diff --git a/core/src/utils/ec/uint256.rs b/crates/curves/src/uint256.rs similarity index 91% rename from core/src/utils/ec/uint256.rs rename to crates/curves/src/uint256.rs index 5618622de5..a55813a226 100644 --- a/core/src/utils/ec/uint256.rs +++ b/crates/curves/src/uint256.rs @@ -3,7 +3,7 @@ use typenum::{U32, U63}; use num::{BigUint, One}; use serde::{Deserialize, Serialize}; -use crate::operations::field::params::{FieldParameters, NumLimbs}; +use crate::params::{FieldParameters, NumLimbs}; /// Although `U256` is technically not a field, we utilize `FieldParameters` here for compatibility. /// This approach is specifically for the `FieldOps` multiplication operation, which employs these @@ -29,6 +29,7 @@ impl FieldParameters for U256Field { impl NumLimbs for U256Field { type Limbs = U32; - // Note we use one more limb than usual because for mulmod with mod 1<<256, we need an extra limb. + // Note we use one more limb than usual because for mulmod with mod 1<<256, we need an extra + // limb. type Witness = U63; } diff --git a/core/src/utils/ec/utils.rs b/crates/curves/src/utils.rs similarity index 86% rename from core/src/utils/ec/utils.rs rename to crates/curves/src/utils.rs index 523fa8b10b..23a19c11f9 100644 --- a/core/src/utils/ec/utils.rs +++ b/crates/curves/src/utils.rs @@ -8,10 +8,7 @@ pub fn biguint_to_bits_le(integer: &BigUint, num_bits: usize) -> Vec { bits.push(byte & (1 << i) != 0); } } - debug_assert!( - bits.len() <= num_bits, - "Number too large to fit in {num_bits} digits" - ); + debug_assert!(bits.len() <= num_bits, "Number too large to fit in {num_bits} digits"); bits.resize(num_bits, false); bits } diff --git a/core/src/utils/ec/weierstrass/bls12_381.rs b/crates/curves/src/weierstrass/bls12_381.rs similarity index 92% rename from core/src/utils/ec/weierstrass/bls12_381.rs rename to crates/curves/src/weierstrass/bls12_381.rs index 1234024224..0f90a91a0d 100644 --- a/core/src/utils/ec/weierstrass/bls12_381.rs +++ b/crates/curves/src/weierstrass/bls12_381.rs @@ -1,19 +1,17 @@ -use amcl::bls381::big::Big; -use amcl::bls381::bls381::utils::deserialize_g1; -use amcl::bls381::fp::FP; +use amcl::bls381::{big::Big, bls381::utils::deserialize_g1, fp::FP}; use generic_array::GenericArray; use num::{BigUint, Num, Zero}; use serde::{Deserialize, Serialize}; use typenum::{U48, U94}; -use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::FieldParameters; -use crate::operations::field::params::NumLimbs; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurveParameters; +use super::{FieldType, FpOpField, SwCurve, WeierstrassParameters}; +use crate::{ + params::{FieldParameters, NumLimbs}, + CurveType, EllipticCurveParameters, +}; /// Bls12-381 curve parameter -use crate::utils::ec::{AffinePoint, EllipticCurve}; +use crate::{AffinePoint, EllipticCurve}; // Serialization flags const COMPRESION_FLAG: u8 = 0b_1000_0000; @@ -53,6 +51,10 @@ impl FieldParameters for Bls12381BaseField { } } +impl FpOpField for Bls12381BaseField { + const FIELD_TYPE: FieldType = FieldType::Bls12381; +} + impl NumLimbs for Bls12381BaseField { type Limbs = U48; type Witness = U94; @@ -142,7 +144,7 @@ mod tests { use amcl::bls381::bls381::proof_of_possession::G1_BYTES; use super::*; - use crate::utils::ec::utils::biguint_from_limbs; + use crate::utils::biguint_from_limbs; use num::bigint::RandBigInt; use rand::thread_rng; @@ -150,10 +152,7 @@ mod tests { #[test] fn test_weierstrass_biguint_scalar_mul() { - assert_eq!( - biguint_from_limbs(Bls12381BaseField::MODULUS), - Bls12381BaseField::modulus() - ); + assert_eq!(biguint_from_limbs(Bls12381BaseField::MODULUS), Bls12381BaseField::modulus()); } #[test] diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/crates/curves/src/weierstrass/bn254.rs similarity index 86% rename from core/src/utils/ec/weierstrass/bn254.rs rename to crates/curves/src/weierstrass/bn254.rs index 7abe574c84..a2dd2aa32c 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/crates/curves/src/weierstrass/bn254.rs @@ -3,11 +3,11 @@ use num::{BigUint, Num, Zero}; use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; -use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::FieldParameters; -use crate::operations::field::params::NumLimbs; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurveParameters; +use super::{FieldType, FpOpField, SwCurve, WeierstrassParameters}; +use crate::{ + params::{FieldParameters, NumLimbs}, + CurveType, EllipticCurveParameters, +}; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Bn254 curve parameter @@ -39,6 +39,10 @@ impl FieldParameters for Bn254BaseField { } } +impl FpOpField for Bn254BaseField { + const FIELD_TYPE: FieldType = FieldType::Bn254; +} + impl NumLimbs for Bn254BaseField { type Limbs = U32; type Witness = U62; @@ -89,13 +93,10 @@ impl WeierstrassParameters for Bn254Parameters { mod tests { use super::*; - use crate::utils::ec::utils::biguint_from_limbs; + use crate::utils::biguint_from_limbs; #[test] fn test_weierstrass_biguint_scalar_mul() { - assert_eq!( - biguint_from_limbs(Bn254BaseField::MODULUS), - Bn254BaseField::modulus() - ); + assert_eq!(biguint_from_limbs(Bn254BaseField::MODULUS), Bn254BaseField::modulus()); } } diff --git a/core/src/utils/ec/weierstrass/mod.rs b/crates/curves/src/weierstrass/mod.rs similarity index 62% rename from core/src/utils/ec/weierstrass/mod.rs rename to crates/curves/src/weierstrass/mod.rs index 5ab6f47ae5..266a93c1ca 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/crates/curves/src/weierstrass/mod.rs @@ -3,10 +3,11 @@ use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; use super::CurveType; -use crate::operations::field::params::FieldParameters; -use crate::operations::field::params::NumLimbs; -use crate::utils::ec::utils::biguint_to_bits_le; -use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; +use crate::{ + params::{FieldParameters, NumLimbs, NumWords}, + utils::biguint_to_bits_le, + AffinePoint, EllipticCurve, EllipticCurveParameters, +}; pub mod bls12_381; pub mod bn254; @@ -134,40 +135,95 @@ impl AffinePoint> { } } +pub fn biguint_to_dashu(integer: &BigUint) -> dashu::integer::UBig { + dashu::integer::UBig::from_le_bytes(integer.to_bytes_le().as_slice()) +} + +pub fn dashu_to_biguint(integer: &dashu::integer::UBig) -> BigUint { + BigUint::from_bytes_le(&integer.to_le_bytes()) +} + +pub fn dashu_modpow( + base: &dashu::integer::UBig, + exponent: &dashu::integer::UBig, + modulus: &dashu::integer::UBig, +) -> dashu::integer::UBig { + if modulus == &dashu::integer::UBig::from(1u32) { + return dashu::integer::UBig::from(0u32); + } + + let mut result = dashu::integer::UBig::from(1u32); + let mut base = base.clone() % modulus; + let mut exp = exponent.clone(); + + while exp > dashu::integer::UBig::from(0u32) { + if &exp % dashu::integer::UBig::from(2u32) == dashu::integer::UBig::from(1u32) { + result = (result * &base) % modulus; + } + exp >>= 1; + base = (&base * &base) % modulus; + } + + result +} + impl AffinePoint> { pub fn sw_add(&self, other: &AffinePoint>) -> AffinePoint> { if self.x == other.x && self.y == other.y { panic!("Error: Points are the same. Use sw_double instead."); } - let p = E::BaseField::modulus(); - let slope_numerator = (&p + &other.y - &self.y) % &p; - let slope_denominator = (&p + &other.x - &self.x) % &p; - let slope_denom_inverse = slope_denominator.modpow(&(&p - 2u32), &p); + + let p = biguint_to_dashu(&E::BaseField::modulus()); + let self_x = biguint_to_dashu(&self.x); + let self_y = biguint_to_dashu(&self.y); + let other_x = biguint_to_dashu(&other.x); + let other_y = biguint_to_dashu(&other.y); + + let slope_numerator = (&p + &other_y - &self_y) % &p; + let slope_denominator = (&p + &other_x - &self_x) % &p; + let slope_denom_inverse = + dashu_modpow(&slope_denominator, &(&p - &dashu::integer::UBig::from(2u32)), &p); let slope = (slope_numerator * &slope_denom_inverse) % &p; - let x_3n = (&slope * &slope + &p + &p - &self.x - &other.x) % &p; - let y_3n = (&slope * &(&p + &self.x - &x_3n) + &p - &self.y) % &p; + let x_3n = (&slope * &slope + &p + &p - &self_x - &other_x) % &p; + let y_3n = (&slope * &(&p + &self_x - &x_3n) + &p - &self_y) % &p; - AffinePoint::new(x_3n, y_3n) + AffinePoint::new(dashu_to_biguint(&x_3n), dashu_to_biguint(&y_3n)) } pub fn sw_double(&self) -> AffinePoint> { - let p = E::BaseField::modulus(); - let a = E::a_int(); - let slope_numerator = (&a + &(&self.x * &self.x) * 3u32) % &p; + let p = biguint_to_dashu(&E::BaseField::modulus()); + let a = biguint_to_dashu(&E::a_int()); + + let self_x = biguint_to_dashu(&self.x); + let self_y = biguint_to_dashu(&self.y); - let slope_denominator = (&self.y * 2u32) % &p; - let slope_denom_inverse = slope_denominator.modpow(&(&p - 2u32), &p); + let slope_numerator = (&a + &(&self_x * &self_x) * 3u32) % &p; + + let slope_denominator = (&self_y * 2u32) % &p; + let slope_denom_inverse = + dashu_modpow(&slope_denominator, &(&p - &dashu::integer::UBig::from(2u32)), &p); + // let slope_denom_inverse = slope_denominator.modpow(&(&p - 2u32), &p); let slope = (slope_numerator * &slope_denom_inverse) % &p; - let x_3n = (&slope * &slope + &p + &p - &self.x - &self.x) % &p; + let x_3n = (&slope * &slope + &p + &p - &self_x - &self_x) % &p; - let y_3n = (&slope * &(&p + &self.x - &x_3n) + &p - &self.y) % &p; + let y_3n = (&slope * &(&p + &self_x - &x_3n) + &p - &self_y) % &p; - AffinePoint::new(x_3n, y_3n) + AffinePoint::new(dashu_to_biguint(&x_3n), dashu_to_biguint(&y_3n)) } } +#[derive(Debug)] +pub enum FieldType { + Bls12381, + Bn254, +} + +pub trait FpOpField: FieldParameters + NumWords { + const FIELD_TYPE: FieldType; +} + #[cfg(test)] mod tests { diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/crates/curves/src/weierstrass/secp256k1.rs similarity index 85% rename from core/src/utils/ec/weierstrass/secp256k1.rs rename to crates/curves/src/weierstrass/secp256k1.rs index 1731beaa65..d6514caa65 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/crates/curves/src/weierstrass/secp256k1.rs @@ -3,24 +3,21 @@ use std::str::FromStr; -use elliptic_curve::sec1::ToEncodedPoint; -use elliptic_curve::subtle::Choice; +use elliptic_curve::{sec1::ToEncodedPoint, subtle::Choice}; use generic_array::GenericArray; -use k256::elliptic_curve::point::DecompressPoint; -use k256::FieldElement; -use num::traits::FromBytes; -use num::traits::ToBytes; -use num::{BigUint, Zero}; +use k256::{elliptic_curve::point::DecompressPoint, FieldElement}; +use num::{ + traits::{FromBytes, ToBytes}, + BigUint, Zero, +}; use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::FieldParameters; -use crate::operations::field::params::NumLimbs; -use crate::utils::ec::AffinePoint; -use crate::utils::ec::CurveType; -use crate::utils::ec::EllipticCurve; -use crate::utils::ec::EllipticCurveParameters; +use crate::{ + params::{FieldParameters, NumLimbs}, + AffinePoint, CurveType, EllipticCurve, EllipticCurveParameters, +}; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Secp256k1 curve parameter @@ -118,16 +115,13 @@ pub fn secp256k1_sqrt(n: &BigUint) -> BigUint { mod tests { use super::*; - use crate::utils::ec::utils::biguint_from_limbs; + use crate::utils::biguint_from_limbs; use num::bigint::RandBigInt; use rand::thread_rng; #[test] fn test_weierstrass_biguint_scalar_mul() { - assert_eq!( - biguint_from_limbs(Secp256k1BaseField::MODULUS), - Secp256k1BaseField::modulus() - ); + assert_eq!(biguint_from_limbs(Secp256k1BaseField::MODULUS), Secp256k1BaseField::modulus()); } #[test] diff --git a/derive/CHANGELOG.md b/crates/derive/CHANGELOG.md similarity index 100% rename from derive/CHANGELOG.md rename to crates/derive/CHANGELOG.md diff --git a/derive/Cargo.toml b/crates/derive/Cargo.toml similarity index 94% rename from derive/Cargo.toml rename to crates/derive/Cargo.toml index 88e1f95211..23f2facd54 100644 --- a/derive/Cargo.toml +++ b/crates/derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-derive" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +readme = "../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } diff --git a/derive/src/lib.rs b/crates/derive/src/lib.rs similarity index 86% rename from derive/src/lib.rs rename to crates/derive/src/lib.rs index a621e0ac1e..1896c312ef 100644 --- a/derive/src/lib.rs +++ b/crates/derive/src/lib.rs @@ -26,13 +26,9 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::parse_macro_input; -use syn::parse_quote; -use syn::Data; -use syn::DeriveInput; -use syn::GenericParam; -use syn::ItemFn; -use syn::WherePredicate; +use syn::{ + parse_macro_input, parse_quote, Data, DeriveInput, GenericParam, ItemFn, WherePredicate, +}; #[proc_macro_derive(AlignedBorrow)] pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { @@ -65,7 +61,8 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { }) .collect::>(); - // Get impl generics (``), type generics (``), where clause (`where T: Clone`) + // Get impl generics (``), type generics (``), where + // clause (`where T: Clone`) let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let methods = quote! { @@ -95,20 +92,13 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { #[proc_macro_derive( MachineAir, - attributes( - sp1_core_path, - execution_record_path, - program_path, - builder_path, - eval_trait_bound - ) + attributes(sp1_core_path, execution_record_path, program_path, builder_path, eval_trait_bound) )] pub fn machine_air_derive(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let generics = &ast.generics; - let sp1_core_path = find_sp1_core_path(&ast.attrs); let execution_record_path = find_execution_record_path(&ast.attrs); let program_path = find_program_path(&ast.attrs); let builder_path = find_builder_path(&ast.attrs); @@ -155,47 +145,47 @@ pub fn machine_air_derive(input: TokenStream) -> TokenStream { let name_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::name(x) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::name(x) } }); let preprocessed_width_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::preprocessed_width(x) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::preprocessed_width(x) } }); let generate_preprocessed_trace_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::generate_preprocessed_trace(x, program) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::generate_preprocessed_trace(x, program) } }); let generate_trace_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::generate_trace(x, input, output) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::generate_trace(x, input, output) } }); let generate_dependencies_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::generate_dependencies(x, input, output) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::generate_dependencies(x, input, output) } }); let included_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { - #name::#variant_name(x) => <#field_ty as #sp1_core_path::air::MachineAir>::included(x, shard) + #name::#variant_name(x) => <#field_ty as sp1_stark::air::MachineAir>::included(x, shard) } }); let machine_air = quote! { - impl #impl_generics #sp1_core_path::air::MachineAir for #name #ty_generics #where_clause { + impl #impl_generics sp1_stark::air::MachineAir for #name #ty_generics #where_clause { type Record = #execution_record_path; type Program = #program_path; @@ -259,9 +249,7 @@ pub fn machine_air_derive(input: TokenStream) -> TokenStream { // Attach an extra generic AB : crate::air::SP1AirBuilder to the generics of the enum let generics = &ast.generics; let mut new_generics = generics.clone(); - new_generics - .params - .push(syn::parse_quote! { AB: p3_air::PairBuilder + #builder_path }); + new_generics.params.push(syn::parse_quote! { AB: p3_air::PairBuilder + #builder_path }); let (air_impl_generics, _, _) = new_generics.split_for_impl(); @@ -318,19 +306,6 @@ pub fn cycle_tracker(_attr: TokenStream, item: TokenStream) -> TokenStream { result.into() } -fn find_sp1_core_path(attrs: &[syn::Attribute]) -> syn::Ident { - for attr in attrs { - if attr.path.is_ident("sp1_core_path") { - if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { - if let syn::Lit::Str(lit_str) = &meta.lit { - return syn::Ident::new(&lit_str.value(), lit_str.span()); - } - } - } - } - syn::Ident::new("crate", proc_macro2::Span::call_site()) -} - fn find_execution_record_path(attrs: &[syn::Attribute]) -> syn::Path { for attr in attrs { if attr.path.is_ident("execution_record_path") { @@ -343,7 +318,7 @@ fn find_execution_record_path(attrs: &[syn::Attribute]) -> syn::Path { } } } - parse_quote!(crate::runtime::ExecutionRecord) + parse_quote!(sp1_core_executor::ExecutionRecord) } fn find_program_path(attrs: &[syn::Attribute]) -> syn::Path { @@ -358,7 +333,7 @@ fn find_program_path(attrs: &[syn::Attribute]) -> syn::Path { } } } - parse_quote!(crate::runtime::Program) + parse_quote!(sp1_core_executor::Program) } fn find_builder_path(attrs: &[syn::Attribute]) -> syn::Path { @@ -373,7 +348,7 @@ fn find_builder_path(attrs: &[syn::Attribute]) -> syn::Path { } } } - parse_quote!(crate::air::SP1AirBuilder) + parse_quote!(crate::air::SP1CoreAirBuilder) } fn find_eval_trait_bound(attrs: &[syn::Attribute]) -> Option { diff --git a/helper/CHANGELOG.md b/crates/helper/CHANGELOG.md similarity index 100% rename from helper/CHANGELOG.md rename to crates/helper/CHANGELOG.md diff --git a/helper/Cargo.toml b/crates/helper/Cargo.toml similarity index 72% rename from helper/Cargo.toml rename to crates/helper/Cargo.toml index 5d8d588257..d87951d3e3 100644 --- a/helper/Cargo.toml +++ b/crates/helper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-helper" description = "Crate for building SP1 programs with build scripts." -readme = "../README.md" +readme = "../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -9,7 +9,8 @@ repository = { workspace = true } keywords = { workspace = true } categories = { workspace = true } +[package.metadata] +deprecated = "This crate is deprecated. Please use sp1_build instead." + [dependencies] sp1-build = { workspace = true } -cargo_metadata = "0.18.1" -chrono = { version = "0.4.38", default-features = false, features = ["clock"] } diff --git a/crates/helper/src/lib.rs b/crates/helper/src/lib.rs new file mode 100644 index 0000000000..663042414f --- /dev/null +++ b/crates/helper/src/lib.rs @@ -0,0 +1,5 @@ +#[deprecated( + since = "1.2.0", + note = "Please use `sp1_build::build_program`, `sp1_build::build_program_with_args` and `sp1_build::BuildArgs` directly" +)] +pub use sp1_build::{build_program, build_program_with_args, BuildArgs}; diff --git a/primitives/CHANGELOG.md b/crates/primitives/CHANGELOG.md similarity index 100% rename from primitives/CHANGELOG.md rename to crates/primitives/CHANGELOG.md diff --git a/primitives/Cargo.toml b/crates/primitives/Cargo.toml similarity index 94% rename from primitives/Cargo.toml rename to crates/primitives/Cargo.toml index f52956802b..e8b6c7bf89 100644 --- a/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-primitives" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +readme = "../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } diff --git a/crates/primitives/src/consts.rs b/crates/primitives/src/consts.rs new file mode 100644 index 0000000000..396905274b --- /dev/null +++ b/crates/primitives/src/consts.rs @@ -0,0 +1,56 @@ +/// The maximum size of the memory in bytes. +pub const MAXIMUM_MEMORY_SIZE: u32 = u32::MAX; + +/// The size of a word in bytes. +pub const WORD_SIZE: usize = 4; + +/// Converts a slice of words to a byte vector in little endian. +pub fn words_to_bytes_le_vec(words: &[u32]) -> Vec { + words.iter().flat_map(|word| word.to_le_bytes().to_vec()).collect::>() +} + +/// Converts a slice of words to a slice of bytes in little endian. +pub fn words_to_bytes_le(words: &[u32]) -> [u8; B] { + debug_assert_eq!(words.len() * 4, B); + words + .iter() + .flat_map(|word| word.to_le_bytes().to_vec()) + .collect::>() + .try_into() + .unwrap() +} + +/// Converts a byte array in little endian to a slice of words. +pub fn bytes_to_words_le(bytes: &[u8]) -> [u32; W] { + debug_assert_eq!(bytes.len(), W * 4); + bytes + .chunks_exact(4) + .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) + .collect::>() + .try_into() + .unwrap() +} + +/// Converts a byte array in little endian to a vector of words. +pub fn bytes_to_words_le_vec(bytes: &[u8]) -> Vec { + bytes + .chunks_exact(4) + .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) + .collect::>() +} + +// Converts a num to a string with commas every 3 digits. +pub fn num_to_comma_separated(value: T) -> String { + value + .to_string() + .chars() + .rev() + .collect::>() + .chunks(3) + .map(|chunk| chunk.iter().collect::()) + .collect::>() + .join(",") + .chars() + .rev() + .collect() +} diff --git a/primitives/src/lib.rs b/crates/primitives/src/lib.rs similarity index 99% rename from primitives/src/lib.rs rename to crates/primitives/src/lib.rs index cd89a5134e..190524acdf 100644 --- a/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -6,6 +6,7 @@ use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_field::AbstractField; use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +pub mod consts; pub mod types; lazy_static! { @@ -1108,10 +1109,8 @@ pub fn poseidon2_init( let mut round_constants = RC_16_30.to_vec(); let internal_start = ROUNDS_F / 2; let internal_end = (ROUNDS_F / 2) + ROUNDS_P; - let internal_round_constants = round_constants - .drain(internal_start..internal_end) - .map(|vec| vec[0]) - .collect::>(); + let internal_round_constants = + round_constants.drain(internal_start..internal_end).map(|vec| vec[0]).collect::>(); let external_round_constants = round_constants; Poseidon2::new( ROUNDS_F, diff --git a/primitives/src/types.rs b/crates/primitives/src/types.rs similarity index 100% rename from primitives/src/types.rs rename to crates/primitives/src/types.rs diff --git a/prover/CHANGELOG.md b/crates/prover/CHANGELOG.md similarity index 100% rename from prover/CHANGELOG.md rename to crates/prover/CHANGELOG.md diff --git a/prover/Cargo.toml b/crates/prover/Cargo.toml similarity index 84% rename from prover/Cargo.toml rename to crates/prover/Cargo.toml index e5e0fd552e..a848d986d5 100644 --- a/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-prover" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../README.md" +readme = "../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -16,7 +16,9 @@ sp1-recursion-circuit = { workspace = true } sp1-recursion-compiler = { workspace = true } sp1-recursion-core = { workspace = true } sp1-recursion-gnark-ffi = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } +sp1-stark = { workspace = true } +sp1-core-executor = { workspace = true } sp1-primitives = { workspace = true } p3-field = { workspace = true } p3-challenger = { workspace = true } @@ -45,11 +47,15 @@ oneshot = "0.1.8" name = "build_plonk_bn254" path = "scripts/build_plonk_bn254.rs" +[[bin]] +name = "build_groth16_bn254" +path = "scripts/build_groth16_bn254.rs" + [[bin]] name = "e2e" path = "scripts/e2e.rs" [features] -neon = ["sp1-core/neon"] +neon = ["sp1-core-machine/neon"] native-gnark = ["sp1-recursion-gnark-ffi/native"] export-tests = [] diff --git a/prover/Makefile b/crates/prover/Makefile similarity index 64% rename from prover/Makefile rename to crates/prover/Makefile index 8ab442e38b..9365179916 100644 --- a/prover/Makefile +++ b/crates/prover/Makefile @@ -1,15 +1,18 @@ all: - make build-plonk-bn254 - make release-plonk-bn254 + make build-circuits + make release-circuits -build-plonk-bn254: +build-circuits: rm -rf build && \ mkdir -p build && \ RUSTFLAGS='-C target-cpu=native' \ cargo run -p sp1-prover --release --bin build_plonk_bn254 --features native-gnark -- \ + --build-dir=./build && \ + RUSTFLAGS='-C target-cpu=native' \ + cargo run -p sp1-prover --release --bin build_groth16_bn254 --features native-gnark -- \ --build-dir=./build -release-plonk-bn254: +release-circuits: @read -p "Release version (ex. v1.0.0-testnet)? " version; \ bash release.sh $$version diff --git a/prover/elf/riscv32im-succinct-zkvm-elf b/crates/prover/elf/riscv32im-succinct-zkvm-elf similarity index 100% rename from prover/elf/riscv32im-succinct-zkvm-elf rename to crates/prover/elf/riscv32im-succinct-zkvm-elf diff --git a/prover/release.sh b/crates/prover/release.sh similarity index 100% rename from prover/release.sh rename to crates/prover/release.sh diff --git a/prover/scripts/.gitignore b/crates/prover/scripts/.gitignore similarity index 100% rename from prover/scripts/.gitignore rename to crates/prover/scripts/.gitignore diff --git a/prover/scripts/artifacts/example_proof.json b/crates/prover/scripts/artifacts/example_proof.json similarity index 100% rename from prover/scripts/artifacts/example_proof.json rename to crates/prover/scripts/artifacts/example_proof.json diff --git a/prover/scripts/artifacts/example_vk_groth16.bin b/crates/prover/scripts/artifacts/example_vk_groth16.bin similarity index 100% rename from prover/scripts/artifacts/example_vk_groth16.bin rename to crates/prover/scripts/artifacts/example_vk_groth16.bin diff --git a/crates/prover/scripts/build_groth16_bn254.rs b/crates/prover/scripts/build_groth16_bn254.rs new file mode 100644 index 0000000000..e7b5e1e61f --- /dev/null +++ b/crates/prover/scripts/build_groth16_bn254.rs @@ -0,0 +1,18 @@ +use std::path::PathBuf; + +use clap::Parser; +use sp1_core_machine::utils::setup_logger; +use sp1_prover::build::build_groth16_bn254_artifacts_with_dummy; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + #[clap(short, long)] + build_dir: PathBuf, +} + +pub fn main() { + setup_logger(); + let args = Args::parse(); + build_groth16_bn254_artifacts_with_dummy(args.build_dir); +} diff --git a/prover/scripts/build_plonk_bn254.rs b/crates/prover/scripts/build_plonk_bn254.rs similarity index 89% rename from prover/scripts/build_plonk_bn254.rs rename to crates/prover/scripts/build_plonk_bn254.rs index e81d621479..17d1f9ba19 100644 --- a/prover/scripts/build_plonk_bn254.rs +++ b/crates/prover/scripts/build_plonk_bn254.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use clap::Parser; -use sp1_core::utils::setup_logger; +use sp1_core_machine::utils::setup_logger; use sp1_prover::build::build_plonk_bn254_artifacts_with_dummy; #[derive(Parser, Debug)] diff --git a/prover/scripts/e2e.rs b/crates/prover/scripts/e2e.rs similarity index 58% rename from prover/scripts/e2e.rs rename to crates/prover/scripts/e2e.rs index f6cd434aa2..3476ce89e7 100644 --- a/prover/scripts/e2e.rs +++ b/crates/prover/scripts/e2e.rs @@ -1,19 +1,19 @@ -use std::borrow::Borrow; -use std::path::PathBuf; +use std::{borrow::Borrow, path::PathBuf}; use clap::Parser; use p3_baby_bear::BabyBear; use p3_field::PrimeField; -use sp1_core::io::SP1Stdin; -use sp1_core::runtime::SP1Context; -use sp1_core::utils::SP1ProverOpts; -use sp1_prover::utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}; -use sp1_prover::SP1Prover; -use sp1_recursion_circuit::stark::build_wrap_circuit; -use sp1_recursion_circuit::witness::Witnessable; +use sp1_core_executor::SP1Context; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::{ + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + SP1Prover, +}; +use sp1_recursion_circuit::{stark::build_wrap_circuit, witness::Witnessable}; use sp1_recursion_compiler::ir::Witness; use sp1_recursion_core::air::RecursionPublicValues; -use sp1_recursion_gnark_ffi::PlonkBn254Prover; +use sp1_recursion_gnark_ffi::{Groth16Bn254Prover, PlonkBn254Prover}; +use sp1_stark::SP1ProverOpts; use subtle_encoding::hex; #[derive(Parser, Debug)] @@ -21,10 +21,12 @@ use subtle_encoding::hex; struct Args { #[clap(short, long)] build_dir: String, + #[arg(short, long)] + system: String, } pub fn main() { - sp1_core::utils::setup_logger(); + sp1_core_machine::utils::setup_logger(); std::env::set_var("RECONSTRUCT_COMMITMENTS", "false"); let args = Args::parse(); @@ -60,9 +62,8 @@ pub fn main() { tracing::info!("building template witness"); let pv: &RecursionPublicValues<_> = wrapped_proof.proof.public_values.as_slice().borrow(); let vkey_hash = babybears_to_bn254(&pv.sp1_vk_digest); - let committed_values_digest_bytes: [BabyBear; 32] = words_to_bytes(&pv.committed_value_digest) - .try_into() - .unwrap(); + let committed_values_digest_bytes: [BabyBear; 32] = + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); let committed_values_digest = babybear_bytes_to_bn254(&committed_values_digest_bytes); let mut witness = Witness::default(); @@ -70,19 +71,19 @@ pub fn main() { witness.write_commited_values_digest(committed_values_digest); witness.write_vkey_hash(vkey_hash); - tracing::info!("sanity check gnark test"); + tracing::info!("sanity check plonk test"); PlonkBn254Prover::test(constraints.clone(), witness.clone()); - tracing::info!("sanity check gnark build"); + tracing::info!("sanity check plonk build"); PlonkBn254Prover::build(constraints.clone(), witness.clone(), build_dir.clone()); - tracing::info!("sanity check gnark prove"); + tracing::info!("sanity check plonk prove"); let plonk_bn254_prover = PlonkBn254Prover::new(); - tracing::info!("gnark prove"); + tracing::info!("plonk prove"); let proof = plonk_bn254_prover.prove(witness.clone(), build_dir.clone()); - tracing::info!("verify gnark proof"); + tracing::info!("verify plonk proof"); plonk_bn254_prover.verify( &proof, &vkey_hash.as_canonical_biguint(), @@ -90,8 +91,27 @@ pub fn main() { &build_dir, ); - println!( - "{:?}", - String::from_utf8(hex::encode(proof.encoded_proof)).unwrap() + println!("plonk proof: {:?}", String::from_utf8(hex::encode(proof.encoded_proof)).unwrap()); + + tracing::info!("sanity check groth16 test"); + Groth16Bn254Prover::test(constraints.clone(), witness.clone()); + + tracing::info!("sanity check groth16 build"); + Groth16Bn254Prover::build(constraints.clone(), witness.clone(), build_dir.clone()); + + tracing::info!("sanity check groth16 prove"); + let groth16_bn254_prover = Groth16Bn254Prover::new(); + + tracing::info!("groth16 prove"); + let proof = groth16_bn254_prover.prove(witness.clone(), build_dir.clone()); + + tracing::info!("verify groth16 proof"); + groth16_bn254_prover.verify( + &proof, + &vkey_hash.as_canonical_biguint(), + &committed_values_digest.as_canonical_biguint(), + &build_dir, ); + + println!("groth16 proof: {:?}", String::from_utf8(hex::encode(proof.encoded_proof)).unwrap()); } diff --git a/prover/scripts/fibonacci_groth16.rs b/crates/prover/scripts/fibonacci_groth16.rs similarity index 99% rename from prover/scripts/fibonacci_groth16.rs rename to crates/prover/scripts/fibonacci_groth16.rs index fb5454274c..66e7cdc3c8 100644 --- a/prover/scripts/fibonacci_groth16.rs +++ b/crates/prover/scripts/fibonacci_groth16.rs @@ -3,7 +3,7 @@ use std::time::Instant; use itertools::iproduct; -use sp1_core::{ +use sp1_core_machine::{ io::SP1Stdin, utils::{SP1ProverOpts, SP1ProverOpts}, }; diff --git a/prover/scripts/fibonacci_sweep.rs b/crates/prover/scripts/fibonacci_sweep.rs similarity index 99% rename from prover/scripts/fibonacci_sweep.rs rename to crates/prover/scripts/fibonacci_sweep.rs index 687d7e518d..6f752a80f0 100644 --- a/prover/scripts/fibonacci_sweep.rs +++ b/crates/prover/scripts/fibonacci_sweep.rs @@ -3,7 +3,7 @@ use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; -use sp1_core::{ +use sp1_core_machine::{ io::SP1Stdin, utils::{SP1ProverOpts, SP1ProverOpts}, }; diff --git a/prover/scripts/tendermint_sweep.rs b/crates/prover/scripts/tendermint_sweep.rs similarity index 99% rename from prover/scripts/tendermint_sweep.rs rename to crates/prover/scripts/tendermint_sweep.rs index efdcad88aa..13f2308b69 100644 --- a/prover/scripts/tendermint_sweep.rs +++ b/crates/prover/scripts/tendermint_sweep.rs @@ -3,7 +3,7 @@ use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; -use sp1_core::{ +use sp1_core_machine::{ io::SP1Stdin, utils::{SP1ProverOpts, SP1ProverOpts}, }; diff --git a/prover/src/build.rs b/crates/prover/src/build.rs similarity index 60% rename from prover/src/build.rs rename to crates/prover/src/build.rs index feede6518b..39512346b7 100644 --- a/prover/src/build.rs +++ b/crates/prover/src/build.rs @@ -1,21 +1,20 @@ -use std::borrow::Borrow; -use std::path::PathBuf; +use std::{borrow::Borrow, path::PathBuf}; use p3_baby_bear::BabyBear; -use sp1_core::runtime::SP1Context; -use sp1_core::stark::StarkVerifyingKey; -use sp1_core::utils::SP1ProverOpts; -use sp1_core::{io::SP1Stdin, stark::ShardProof}; -pub use sp1_recursion_circuit::stark::build_wrap_circuit; -pub use sp1_recursion_circuit::witness::Witnessable; +use sp1_core_executor::SP1Context; +use sp1_core_machine::io::SP1Stdin; +pub use sp1_recursion_circuit::{stark::build_wrap_circuit, witness::Witnessable}; pub use sp1_recursion_compiler::ir::Witness; use sp1_recursion_compiler::{config::OuterConfig, constraints::Constraint}; use sp1_recursion_core::air::RecursionPublicValues; pub use sp1_recursion_core::stark::utils::sp1_dev_mode; -use sp1_recursion_gnark_ffi::PlonkBn254Prover; +use sp1_recursion_gnark_ffi::{Groth16Bn254Prover, PlonkBn254Prover}; +use sp1_stark::{SP1ProverOpts, ShardProof, StarkVerifyingKey}; -use crate::utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}; -use crate::{OuterSC, SP1Prover}; +use crate::{ + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + OuterSC, SP1Prover, +}; /// Tries to build the PLONK artifacts inside the development directory. pub fn try_build_plonk_bn254_artifacts_dev( @@ -28,18 +27,29 @@ pub fn try_build_plonk_bn254_artifacts_dev( build_dir } +/// Tries to build the groth16 bn254 artifacts in the current environment. +pub fn try_build_groth16_bn254_artifacts_dev( + template_vk: &StarkVerifyingKey, + template_proof: &ShardProof, +) -> PathBuf { + let build_dir = groth16_bn254_artifacts_dev_dir(); + println!("[sp1] building groth16 bn254 artifacts in development mode"); + build_groth16_bn254_artifacts(template_vk, template_proof, &build_dir); + build_dir +} + /// Gets the directory where the PLONK artifacts are installed in development mode. pub fn plonk_bn254_artifacts_dev_dir() -> PathBuf { - dirs::home_dir() - .unwrap() - .join(".sp1") - .join("circuits") - .join("plonk_bn254") - .join("dev") + dirs::home_dir().unwrap().join(".sp1").join("circuits").join("dev") } -/// Build the plonk bn254 artifacts to the given directory for the given verification key and template -/// proof. +/// Gets the directory where the groth16 artifacts are installed in development mode. +pub fn groth16_bn254_artifacts_dev_dir() -> PathBuf { + dirs::home_dir().unwrap().join(".sp1").join("circuits").join("dev") +} + +/// Build the plonk bn254 artifacts to the given directory for the given verification key and +/// template proof. pub fn build_plonk_bn254_artifacts( template_vk: &StarkVerifyingKey, template_proof: &ShardProof, @@ -51,6 +61,19 @@ pub fn build_plonk_bn254_artifacts( PlonkBn254Prover::build(constraints, witness, build_dir); } +/// Build the groth16 bn254 artifacts to the given directory for the given verification key and +/// template proof. +pub fn build_groth16_bn254_artifacts( + template_vk: &StarkVerifyingKey, + template_proof: &ShardProof, + build_dir: impl Into, +) { + let build_dir = build_dir.into(); + std::fs::create_dir_all(&build_dir).expect("failed to create build directory"); + let (constraints, witness) = build_constraints_and_witness(template_vk, template_proof); + Groth16Bn254Prover::build(constraints, witness, build_dir); +} + /// Builds the plonk bn254 artifacts to the given directory. /// /// This may take a while as it needs to first generate a dummy proof and then it needs to compile @@ -60,6 +83,15 @@ pub fn build_plonk_bn254_artifacts_with_dummy(build_dir: impl Into) { crate::build::build_plonk_bn254_artifacts(&wrap_vk, &wrapped_proof, build_dir.into()); } +/// Builds the groth16 bn254 artifacts to the given directory. +/// +/// This may take a while as it needs to first generate a dummy proof and then it needs to compile +/// the circuit. +pub fn build_groth16_bn254_artifacts_with_dummy(build_dir: impl Into) { + let (wrap_vk, wrapped_proof) = dummy_proof(); + crate::build::build_groth16_bn254_artifacts(&wrap_vk, &wrapped_proof, build_dir.into()); +} + /// Build the verifier constraints and template witness for the circuit. pub fn build_constraints_and_witness( template_vk: &StarkVerifyingKey, @@ -71,9 +103,8 @@ pub fn build_constraints_and_witness( let pv: &RecursionPublicValues = template_proof.public_values.as_slice().borrow(); let vkey_hash = babybears_to_bn254(&pv.sp1_vk_digest); - let committed_values_digest_bytes: [BabyBear; 32] = words_to_bytes(&pv.committed_value_digest) - .try_into() - .unwrap(); + let committed_values_digest_bytes: [BabyBear; 32] = + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); let committed_values_digest = babybear_bytes_to_bn254(&committed_values_digest_bytes); tracing::info!("building template witness"); @@ -112,8 +143,5 @@ pub fn dummy_proof() -> (StarkVerifyingKey, ShardProof) { tracing::info!("wrap"); let wrapped_proof = prover.wrap_bn254(shrink_proof, opts).unwrap(); - ( - prover.wrap_keys.into_inner().unwrap().1, - wrapped_proof.proof, - ) + (prover.wrap_keys.into_inner().unwrap().1, wrapped_proof.proof) } diff --git a/prover/src/components.rs b/crates/prover/src/components.rs similarity index 92% rename from prover/src/components.rs rename to crates/prover/src/components.rs index 6cb9d0678d..e88dd87ceb 100644 --- a/prover/src/components.rs +++ b/crates/prover/src/components.rs @@ -1,4 +1,5 @@ -use sp1_core::stark::{CpuProver, MachineProver, RiscvAir, StarkGenericConfig}; +use sp1_core_machine::riscv::RiscvAir; +use sp1_stark::{CpuProver, MachineProver, StarkGenericConfig}; use crate::{CompressAir, CoreSC, InnerSC, OuterSC, ShrinkAir, WrapAir}; diff --git a/prover/src/init.rs b/crates/prover/src/init.rs similarity index 93% rename from prover/src/init.rs rename to crates/prover/src/init.rs index 03be15cdb3..52ca606a22 100644 --- a/prover/src/init.rs +++ b/crates/prover/src/init.rs @@ -1,20 +1,20 @@ use crate::components::SP1ProverComponents; use p3_baby_bear::BabyBear; -pub use sp1_core::io::{SP1PublicValues, SP1Stdin}; -use sp1_core::stark::MachineProver; -use sp1_core::stark::StarkProvingKey; -use sp1_core::stark::StarkVerifyingKey; +pub use sp1_core_machine::io::{SP1PublicValues, SP1Stdin}; use sp1_primitives::types::RecursionProgramType; use sp1_recursion_compiler::config::InnerConfig; use sp1_recursion_core::runtime::RecursionProgram; -pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof; -pub use sp1_recursion_program::machine::ReduceProgramType; +pub use sp1_recursion_gnark_ffi::{ + groth16_bn254::Groth16Bn254Prover, plonk_bn254::PlonkBn254Prover, +}; pub use sp1_recursion_program::machine::{ - SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, SP1RootMemoryLayout, + ReduceProgramType, SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, + SP1RootMemoryLayout, }; use sp1_recursion_program::machine::{ SP1CompressVerifier, SP1DeferredVerifier, SP1RecursiveVerifier, SP1RootVerifier, }; +use sp1_stark::{MachineProver, StarkProvingKey, StarkVerifyingKey}; use tracing::debug_span; use crate::{InnerSC, OuterSC, SP1Prover}; diff --git a/prover/src/lib.rs b/crates/prover/src/lib.rs similarity index 86% rename from prover/src/lib.rs rename to crates/prover/src/lib.rs index c77d7473bb..e147510d49 100644 --- a/prover/src/lib.rs +++ b/crates/prover/src/lib.rs @@ -18,52 +18,51 @@ pub mod types; pub mod utils; pub mod verify; -use std::borrow::Borrow; -use std::path::Path; -use std::sync::mpsc::sync_channel; -use std::sync::{Arc, Mutex, OnceLock}; -use std::thread; +use std::{ + borrow::Borrow, + path::Path, + sync::{mpsc::sync_channel, Arc, Mutex, OnceLock}, + thread, +}; +use crate::init::SP1PublicValues; use components::{DefaultProverComponents, SP1ProverComponents}; use p3_baby_bear::BabyBear; use p3_challenger::CanObserve; use p3_field::{AbstractField, PrimeField}; use p3_matrix::dense::RowMajorMatrix; -use sp1_core::air::{PublicValues, Word}; -pub use sp1_core::io::{SP1PublicValues, SP1Stdin}; -use sp1_core::runtime::{ExecutionError, ExecutionReport, Runtime, SP1Context}; -use sp1_core::stark::MachineProver; -use sp1_core::stark::{Challenge, StarkProvingKey}; -use sp1_core::stark::{Challenger, MachineVerificationError}; -use sp1_core::utils::concurrency::TurnBasedSync; -use sp1_core::utils::{SP1CoreOpts, SP1ProverOpts, DIGEST_SIZE}; -use sp1_core::{ - runtime::Program, - stark::{RiscvAir, ShardProof, StarkGenericConfig, StarkVerifyingKey, Val}, - utils::{BabyBearPoseidon2, SP1CoreProverError}, +use sp1_core_executor::{ExecutionError, ExecutionReport, Executor, Program, SP1Context}; +pub use sp1_core_machine::io::SP1Stdin; +use sp1_core_machine::{ + riscv::RiscvAir, + utils::{concurrency::TurnBasedSync, SP1CoreProverError}, }; use sp1_primitives::hash_deferred_proof; use sp1_recursion_circuit::witness::Witnessable; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::ir::Witness; -use sp1_recursion_core::runtime::ExecutionRecord; +use sp1_recursion_compiler::{config::InnerConfig, ir::Witness}; use sp1_recursion_core::{ air::RecursionPublicValues, - runtime::{RecursionProgram, Runtime as RecursionRuntime}, + runtime::{ExecutionRecord, RecursionProgram, Runtime as RecursionRuntime}, stark::{config::BabyBearPoseidon2Outer, RecursionAir}, }; -pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof; -use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Prover; +pub use sp1_recursion_gnark_ffi::proof::{Groth16Bn254Proof, PlonkBn254Proof}; +use sp1_recursion_gnark_ffi::{groth16_bn254::Groth16Bn254Prover, plonk_bn254::PlonkBn254Prover}; use sp1_recursion_program::hints::Hintable; -pub use sp1_recursion_program::machine::ReduceProgramType; pub use sp1_recursion_program::machine::{ - SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, SP1RootMemoryLayout, + ReduceProgramType, SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, + SP1RootMemoryLayout, +}; +use sp1_stark::{ + air::PublicValues, baby_bear_poseidon2::BabyBearPoseidon2, Challenge, Challenger, + MachineProver, MachineVerificationError, SP1CoreOpts, SP1ProverOpts, ShardProof, + StarkGenericConfig, StarkProvingKey, StarkVerifyingKey, Val, Word, DIGEST_SIZE, }; + use tracing::instrument; pub use types::*; use utils::words_to_bytes; -pub use sp1_core::SP1_CIRCUIT_VERSION; +pub use sp1_core_machine::SP1_CIRCUIT_VERSION; /// The configuration for the core prover. pub type CoreSC = BabyBearPoseidon2; @@ -196,14 +195,10 @@ impl SP1Prover { /// Creates a proving key and a verifying key for a given RISC-V ELF. #[instrument(name = "setup", level = "debug", skip_all)] pub fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - let program = Program::from(elf); + let program = Program::from(elf).unwrap(); let (pk, vk) = self.core_prover.setup(&program); let vk = SP1VerifyingKey { vk }; - let pk = SP1ProvingKey { - pk, - elf: elf.to_vec(), - vk: vk.clone(), - }; + let pk = SP1ProvingKey { pk, elf: elf.to_vec(), vk: vk.clone() }; (pk, vk) } @@ -216,18 +211,15 @@ impl SP1Prover { mut context: SP1Context<'a>, ) -> Result<(SP1PublicValues, ExecutionReport), ExecutionError> { context.subproof_verifier.replace(Arc::new(self)); - let program = Program::from(elf); + let program = Program::from(elf).unwrap(); let opts = SP1CoreOpts::default(); - let mut runtime = Runtime::with_context(program, opts, context); + let mut runtime = Executor::with_context(program, opts, context); runtime.write_vecs(&stdin.buffer); for (proof, vkey) in stdin.proofs.iter() { runtime.write_proof(proof.clone(), vkey.clone()); } - runtime.run_untraced()?; - Ok(( - SP1PublicValues::from(&runtime.state.public_values_stream), - runtime.report, - )) + runtime.run_fast()?; + Ok((SP1PublicValues::from(&runtime.state.public_values_stream), runtime.report)) } /// Generate shard proofs which split up and prove the valid execution of a RISC-V program with @@ -241,9 +233,9 @@ impl SP1Prover { mut context: SP1Context<'a>, ) -> Result { context.subproof_verifier.replace(Arc::new(self)); - let program = Program::from(&pk.elf); + let program = Program::from(&pk.elf).unwrap(); let (proof, public_values_stream, cycles) = - sp1_core::utils::prove_with_context::<_, C::CoreProver>( + sp1_core_machine::utils::prove_with_context::<_, C::CoreProver>( &self.core_prover, &pk.pk, program, @@ -294,18 +286,9 @@ impl SP1Prover { } // Check that the leaf challenger is the same as the reconstruct challenger. - assert_eq!( - reconstruct_challenger.sponge_state, - leaf_challenger.sponge_state - ); - assert_eq!( - reconstruct_challenger.input_buffer, - leaf_challenger.input_buffer - ); - assert_eq!( - reconstruct_challenger.output_buffer, - leaf_challenger.output_buffer - ); + assert_eq!(reconstruct_challenger.sponge_state, leaf_challenger.sponge_state); + assert_eq!(reconstruct_challenger.input_buffer, leaf_challenger.input_buffer); + assert_eq!(reconstruct_challenger.output_buffer, leaf_challenger.output_buffer); core_inputs } @@ -365,12 +348,7 @@ impl SP1Prover { batch_size, is_complete, ); - let last_proof_pv = shard_proofs - .last() - .unwrap() - .public_values - .as_slice() - .borrow(); + let last_proof_pv = shard_proofs.last().unwrap().public_values.as_slice().borrow(); let deferred_inputs = self.get_recursion_deferred_inputs( &vk.vk, leaf_challenger, @@ -381,11 +359,7 @@ impl SP1Prover { let mut inputs = Vec::new(); inputs.extend(core_inputs.into_iter().map(SP1CompressMemoryLayouts::Core)); - inputs.extend( - deferred_inputs - .into_iter() - .map(SP1CompressMemoryLayouts::Deferred), - ); + inputs.extend(deferred_inputs.into_iter().map(SP1CompressMemoryLayouts::Deferred)); inputs } @@ -558,12 +532,10 @@ impl SP1Prover { // Spawn workers who generate the compress proofs. let proofs_sync = Arc::new(TurnBasedSync::new()); - let (proofs_tx, proofs_rx) = sync_channel::<( - usize, - usize, - ShardProof, - ReduceProgramType, - )>(opts.recursion_opts.shard_batch_size); + let (proofs_tx, proofs_rx) = + sync_channel::<(usize, usize, ShardProof, ReduceProgramType)>( + opts.recursion_opts.shard_batch_size, + ); let proofs_tx = Arc::new(Mutex::new(proofs_tx)); let proofs_rx = Arc::new(Mutex::new(proofs_rx)); let mut prover_handles = Vec::new(); @@ -607,9 +579,7 @@ impl SP1Prover { // Generate the proof. let proof = tracing::debug_span!("open").in_scope(|| { - self.compress_prover - .open(pk, data, &mut challenger) - .unwrap() + self.compress_prover.open(pk, data, &mut challenger).unwrap() }); // Wait for our turn to update the state. @@ -655,7 +625,8 @@ impl SP1Prover { // Compute whether we've reached the root of the tree. let is_complete = height == expected_height; - // If it's not complete, and we haven't reached the batch size, continue. + // If it's not complete, and we haven't reached the batch size, + // continue. if !is_complete && batch.len() < batch_size { continue; } @@ -668,15 +639,10 @@ impl SP1Prover { // If we're at the last input of a layer, we need to only include the // first input, otherwise we include all inputs. - let inputs = if is_last { - vec![batch[0].clone()] - } else { - batch.clone() - }; - let shard_proofs = inputs - .iter() - .map(|(_, _, proof, _)| proof.clone()) - .collect(); + let inputs = + if is_last { vec![batch[0].clone()] } else { batch.clone() }; + let shard_proofs = + inputs.iter().map(|(_, _, proof, _)| proof.clone()).collect(); let kinds = inputs .iter() .map(|(_, _, _, program_type)| *program_type) @@ -691,11 +657,7 @@ impl SP1Prover { }); input_sync.wait_for_turn(count); - input_tx - .lock() - .unwrap() - .send((count, inputs[0].1 + 1, input)) - .unwrap(); + input_tx.lock().unwrap().send((count, inputs[0].1 + 1, input)).unwrap(); input_sync.advance_turn(); count += 1; @@ -754,9 +716,7 @@ impl SP1Prover { witness_stream.extend(input.write()); runtime.witness_stream = witness_stream.into(); - runtime - .run() - .map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; + runtime.run().map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; runtime.print_stats(); drop(guard); @@ -764,12 +724,7 @@ impl SP1Prover { let mut recursive_challenger = self.compress_prover.config().challenger(); let proof = self .compress_prover - .prove( - pk, - vec![runtime.record], - &mut recursive_challenger, - opts.recursion_opts, - ) + .prove(pk, vec![runtime.record], &mut recursive_challenger, opts.recursion_opts) .unwrap() .shard_proofs .pop() @@ -803,9 +758,7 @@ impl SP1Prover { runtime.witness_stream = witness_stream.into(); - runtime - .run() - .map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; + runtime.run().map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; runtime.print_stats(); tracing::debug!("Compress program executed successfully"); @@ -822,9 +775,7 @@ impl SP1Prover { ) .unwrap(); - Ok(SP1ReduceProof { - proof: compress_proof.shard_proofs.pop().unwrap(), - }) + Ok(SP1ReduceProof { proof: compress_proof.shard_proofs.pop().unwrap() }) } /// Wrap a reduce proof into a STARK proven over a SNARK-friendly field. @@ -851,9 +802,7 @@ impl SP1Prover { runtime.witness_stream = witness_stream.into(); - runtime - .run() - .map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; + runtime.run().map_err(|e| SP1RecursionProverError::RuntimeError(e.to_string()))?; runtime.print_stats(); tracing::debug!("Wrap program executed successfully"); @@ -863,20 +812,13 @@ impl SP1Prover { let time = std::time::Instant::now(); let mut wrap_proof = self .wrap_prover - .prove( - self.wrap_pk(), - vec![runtime.record], - &mut wrap_challenger, - opts.recursion_opts, - ) + .prove(self.wrap_pk(), vec![runtime.record], &mut wrap_challenger, opts.recursion_opts) .unwrap(); let elapsed = time.elapsed(); tracing::debug!("Wrap proving time: {:?}", elapsed); let mut wrap_challenger = self.wrap_prover.config().challenger(); let result = - self.wrap_prover - .machine() - .verify(self.wrap_vk(), &wrap_proof, &mut wrap_challenger); + self.wrap_prover.machine().verify(self.wrap_vk(), &wrap_proof, &mut wrap_challenger); match result { Ok(_) => tracing::info!("Proof verified successfully"), Err(MachineVerificationError::NonZeroCumulativeSum) => { @@ -886,9 +828,7 @@ impl SP1Prover { } tracing::info!("Wrapping successful"); - Ok(SP1ReduceProof { - proof: wrap_proof.shard_proofs.pop().unwrap(), - }) + Ok(SP1ReduceProof { proof: wrap_proof.shard_proofs.pop().unwrap() }) } /// Wrap the STARK proven over a SNARK-friendly field into a PLONK proof. @@ -920,6 +860,35 @@ impl SP1Prover { proof } + /// Wrap the STARK proven over a SNARK-friendly field into a Groth16 proof. + #[instrument(name = "wrap_groth16_bn254", level = "info", skip_all)] + pub fn wrap_groth16_bn254( + &self, + proof: SP1ReduceProof, + build_dir: &Path, + ) -> Groth16Bn254Proof { + let vkey_digest = proof.sp1_vkey_digest_bn254(); + let commited_values_digest = proof.sp1_commited_values_digest_bn254(); + + let mut witness = Witness::default(); + proof.proof.write(&mut witness); + witness.write_commited_values_digest(commited_values_digest); + witness.write_vkey_hash(vkey_digest); + + let prover = Groth16Bn254Prover::new(); + let proof = prover.prove(witness, build_dir.to_path_buf()); + + // Verify the proof. + prover.verify( + &proof, + &vkey_digest.as_canonical_biguint(), + &commited_values_digest.as_canonical_biguint(), + build_dir, + ); + + proof + } + /// Accumulate deferred proofs into a single digest. pub fn hash_deferred_proofs( prev_digest: [Val; DIGEST_SIZE], @@ -941,7 +910,7 @@ impl SP1Prover { fn check_for_high_cycles(cycles: u64) { if cycles > 100_000_000 { tracing::warn!( - "high cycle count, consider using the prover network for proof generation: https://docs.succinct.xyz/prover-network/setup.html" + "high cycle count, consider using the prover network for proof generation: https://docs.succinct.xyz/generating-proofs/prover-network" ); } } @@ -950,20 +919,22 @@ impl SP1Prover { #[cfg(any(test, feature = "export-tests"))] pub mod tests { - use std::fs::File; - use std::io::{Read, Write}; + use std::{ + fs::File, + io::{Read, Write}, + }; use super::*; use anyhow::Result; - use build::try_build_plonk_bn254_artifacts_dev; + use build::{try_build_groth16_bn254_artifacts_dev, try_build_plonk_bn254_artifacts_dev}; use p3_field::PrimeField32; - use sp1_core::io::SP1Stdin; + use sp1_core_machine::io::SP1Stdin; #[cfg(test)] use serial_test::serial; #[cfg(test)] - use sp1_core::utils::setup_logger; + use sp1_core_machine::utils::setup_logger; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Test { @@ -1020,21 +991,21 @@ pub mod tests { tracing::info!("wrap bn254"); let wrapped_bn254_proof = prover.wrap_bn254(shrink_proof, opts)?; - let bytes = bincode::serialize(&wrapped_bn254_proof).unwrap(); + let bytes = bincode::serialize(&wrapped_bn254_proof)?; // Save the proof. - let mut file = File::create("proof-with-pis.bin").unwrap(); - file.write_all(bytes.as_slice()).unwrap(); + let mut file = File::create("proof-with-pis.bin")?; + file.write_all(bytes.as_slice())?; // Load the proof. - let mut file = File::open("proof-with-pis.bin").unwrap(); + let mut file = File::open("proof-with-pis.bin")?; let mut bytes = Vec::new(); - file.read_to_end(&mut bytes).unwrap(); + file.read_to_end(&mut bytes)?; - let wrapped_bn254_proof = bincode::deserialize(&bytes).unwrap(); + let wrapped_bn254_proof = bincode::deserialize(&bytes)?; tracing::info!("verify wrap bn254"); - prover.verify_wrap_bn254(&wrapped_bn254_proof, &vk).unwrap(); + prover.verify_wrap_bn254(&wrapped_bn254_proof, &vk)?; if test_kind == Test::Wrap { return Ok(()); @@ -1051,20 +1022,30 @@ pub mod tests { tracing::info!("generate plonk bn254 proof"); let artifacts_dir = try_build_plonk_bn254_artifacts_dev(prover.wrap_vk(), &wrapped_bn254_proof.proof); - let plonk_bn254_proof = prover.wrap_plonk_bn254(wrapped_bn254_proof, &artifacts_dir); + let plonk_bn254_proof = + prover.wrap_plonk_bn254(wrapped_bn254_proof.clone(), &artifacts_dir); println!("{:?}", plonk_bn254_proof); prover.verify_plonk_bn254(&plonk_bn254_proof, &vk, &public_values, &artifacts_dir)?; + tracing::info!("generate groth16 bn254 proof"); + let artifacts_dir = + try_build_groth16_bn254_artifacts_dev(prover.wrap_vk(), &wrapped_bn254_proof.proof); + let groth16_bn254_proof = prover.wrap_groth16_bn254(wrapped_bn254_proof, &artifacts_dir); + println!("{:?}", groth16_bn254_proof); + + prover.verify_groth16_bn254(&groth16_bn254_proof, &vk, &public_values, &artifacts_dir)?; + Ok(()) } pub fn test_e2e_with_deferred_proofs_prover() -> Result<()> { // Test program which proves the Keccak-256 hash of various inputs. - let keccak_elf = include_bytes!("../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf"); + let keccak_elf = include_bytes!("../../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf"); // Test program which verifies proofs of a vkey and a list of committed inputs. - let verify_elf = include_bytes!("../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); + let verify_elf = + include_bytes!("../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf"); tracing::info!("initializing prover"); let prover: SP1Prover = SP1Prover::new(); @@ -1124,11 +1105,7 @@ pub mod tests { let verify_reduce = prover.compress( &verify_vk, verify_proof, - vec![ - deferred_reduce_1.proof, - deferred_reduce_2.proof.clone(), - deferred_reduce_2.proof, - ], + vec![deferred_reduce_1.proof, deferred_reduce_2.proof.clone(), deferred_reduce_2.proof], opts, )?; let reduce_pv: &RecursionPublicValues<_> = @@ -1146,15 +1123,18 @@ pub mod tests { /// pipeline. /// /// Add `FRI_QUERIES`=1 to your environment for faster execution. Should only take a few minutes - /// on a Mac M2. Note: This test always re-builds the plonk bn254 artifacts, so setting SP1_DEV is - /// not needed. + /// on a Mac M2. Note: This test always re-builds the plonk bn254 artifacts, so setting SP1_DEV + /// is not needed. #[test] #[serial] fn test_e2e() -> Result<()> { - let elf = include_bytes!("../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); + let elf = include_bytes!("../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); setup_logger(); let opts = SP1ProverOpts::default(); - test_e2e_prover::(elf, opts, Test::Plonk) + // TODO(mattstam): We should Test::Plonk here, but this uses the existing + // docker image which has a different API than the current. So we need to wait until the + // next release (v1.2.0+), and then switch it back. + test_e2e_prover::(elf, opts, Test::Wrap) } /// Tests an end-to-end workflow of proving a program across the entire proof generation diff --git a/prover/src/types.rs b/crates/prover/src/types.rs similarity index 76% rename from prover/src/types.rs rename to crates/prover/src/types.rs index 6c05934c13..95bc5d8a6c 100644 --- a/prover/src/types.rs +++ b/crates/prover/src/types.rs @@ -1,31 +1,28 @@ -use std::borrow::Borrow; -use std::{fs::File, path::Path}; +use std::{borrow::Borrow, fs::File, path::Path}; use anyhow::Result; use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; -use p3_field::PrimeField; -use p3_field::{AbstractField, PrimeField32, TwoAdicField}; +use p3_field::{AbstractField, PrimeField, PrimeField32, TwoAdicField}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use sp1_core::stark::RiscvAir; -use sp1_core::{ +use sp1_core_machine::{ io::{SP1PublicValues, SP1Stdin}, - stark::{ShardProof, StarkGenericConfig, StarkProvingKey, StarkVerifyingKey}, - utils::DIGEST_SIZE, + riscv::RiscvAir, }; use sp1_primitives::poseidon2_hash; use sp1_recursion_core::{air::RecursionPublicValues, stark::config::BabyBearPoseidon2Outer}; -use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof; +use sp1_recursion_gnark_ffi::proof::{Groth16Bn254Proof, PlonkBn254Proof}; use sp1_recursion_program::machine::{ SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, }; +use sp1_stark::{ShardProof, StarkGenericConfig, StarkProvingKey, StarkVerifyingKey, DIGEST_SIZE}; use thiserror::Error; -use crate::utils::words_to_bytes_be; -use crate::CompressAir; -use crate::{utils::babybear_bytes_to_bn254, words_to_bytes}; -use crate::{utils::babybears_to_bn254, CoreSC, InnerSC}; +use crate::{ + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes_be}, + words_to_bytes, CompressAir, CoreSC, InnerSC, +}; /// The information necessary to generate a proof for a given RISC-V program. #[derive(Clone, Serialize, Deserialize)] @@ -56,10 +53,7 @@ pub trait HashableKey { fn bytes32(&self) -> String { let vkey_digest_bn254 = self.hash_bn254(); - format!( - "0x{:0>64}", - vkey_digest_bn254.as_canonical_biguint().to_str_radix(16) - ) + format!("0x{:0>64}", vkey_digest_bn254.as_canonical_biguint().to_str_radix(16)) } /// Hash the key into a digest of bytes elements. @@ -136,9 +130,7 @@ impl SP1ProofWithMetadata

{ impl std::fmt::Debug for SP1ProofWithMetadata

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("SP1ProofWithMetadata") - .field("proof", &self.proof) - .finish() + f.debug_struct("SP1ProofWithMetadata").field("proof", &self.proof).finish() } } @@ -152,11 +144,15 @@ pub type SP1ReducedProof = SP1ProofWithMetadata; /// An SP1 proof that has been wrapped into a single PLONK proof and can be verified onchain. pub type SP1PlonkBn254Proof = SP1ProofWithMetadata; -/// An SP1 proof that has been wrapped into a single PLONK proof and can be verified onchain. -pub type SP1PlonkProof = SP1ProofWithMetadata; +/// An SP1 proof that has been wrapped into a single Groth16 proof and can be verified onchain. +pub type SP1Groth16Bn254Proof = SP1ProofWithMetadata; + +/// An SP1 proof that has been wrapped into a single proof and can be verified onchain. +pub type SP1Proof = SP1ProofWithMetadata; #[derive(Serialize, Deserialize, Clone)] pub struct SP1CoreProofData(pub Vec>); + #[derive(Serialize, Deserialize, Clone)] pub struct SP1ReducedProofData(pub ShardProof); @@ -164,7 +160,44 @@ pub struct SP1ReducedProofData(pub ShardProof); pub struct SP1PlonkBn254ProofData(pub PlonkBn254Proof); #[derive(Serialize, Deserialize, Clone)] -pub struct SP1PlonkProofData(pub PlonkBn254Proof); +pub struct SP1Groth16Bn254ProofData(pub Groth16Bn254Proof); + +#[derive(Serialize, Deserialize, Clone)] +pub enum SP1Bn254ProofData { + Plonk(PlonkBn254Proof), + Groth16(Groth16Bn254Proof), +} + +impl SP1Bn254ProofData { + pub fn get_proof_system(&self) -> ProofSystem { + match self { + SP1Bn254ProofData::Plonk(_) => ProofSystem::Plonk, + SP1Bn254ProofData::Groth16(_) => ProofSystem::Groth16, + } + } + + pub fn get_raw_proof(&self) -> &str { + match self { + SP1Bn254ProofData::Plonk(proof) => &proof.raw_proof, + SP1Bn254ProofData::Groth16(proof) => &proof.raw_proof, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ProofSystem { + Plonk, + Groth16, +} + +impl ProofSystem { + pub fn as_str(&self) -> &'static str { + match self { + ProofSystem::Plonk => "Plonk", + ProofSystem::Groth16 => "Groth16", + } + } +} /// An intermediate proof which proves the execution over a range of shards. #[derive(Serialize, Deserialize, Clone)] @@ -189,9 +222,7 @@ impl SP1ReduceProof { let proof = &self.proof; let pv: &RecursionPublicValues = proof.public_values.as_slice().borrow(); let committed_values_digest_bytes: [BabyBear; 32] = - words_to_bytes(&pv.committed_value_digest) - .try_into() - .unwrap(); + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); babybear_bytes_to_bn254(&committed_values_digest_bytes) } } diff --git a/prover/src/utils.rs b/crates/prover/src/utils.rs similarity index 89% rename from prover/src/utils.rs rename to crates/prover/src/utils.rs index 34dee12712..9bc0643efd 100644 --- a/prover/src/utils.rs +++ b/crates/prover/src/utils.rs @@ -5,14 +5,10 @@ use std::{ use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use sp1_core::{ - air::Word, - io::SP1Stdin, - runtime::{Program, Runtime}, - utils::SP1CoreOpts, -}; +use p3_field::{AbstractField, PrimeField32}; +use sp1_core_executor::{Executor, Program}; +use sp1_core_machine::io::SP1Stdin; +use sp1_stark::{SP1CoreOpts, Word}; use crate::SP1CoreProofData; @@ -26,10 +22,10 @@ impl SP1CoreProofData { /// Get the number of cycles for a given program. pub fn get_cycles(elf: &[u8], stdin: &SP1Stdin) -> u64 { - let program = Program::from(elf); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); + let program = Program::from(elf).unwrap(); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); runtime.write_vecs(&stdin.buffer); - runtime.dry_run(); + runtime.run_fast().unwrap(); runtime.state.global_clk } diff --git a/prover/src/verify.rs b/crates/prover/src/verify.rs similarity index 80% rename from prover/src/verify.rs rename to crates/prover/src/verify.rs index ed47cee3d3..f9c0817ca3 100644 --- a/prover/src/verify.rs +++ b/crates/prover/src/verify.rs @@ -4,23 +4,23 @@ use anyhow::Result; use num_bigint::BigUint; use p3_baby_bear::BabyBear; use p3_field::{AbstractField, PrimeField}; -use sp1_core::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS, WORD_SIZE}; -use sp1_core::cpu::MAX_CPU_LOG_DEGREE; -use sp1_core::runtime::SubproofVerifier; -use sp1_core::stark::MachineProver; -use sp1_core::{ - air::PublicValues, - io::SP1PublicValues, - stark::{MachineProof, MachineVerificationError, StarkGenericConfig}, - utils::BabyBearPoseidon2, -}; +use sp1_core_executor::subproof::SubproofVerifier; +use sp1_core_machine::{cpu::MAX_CPU_LOG_DEGREE, io::SP1PublicValues}; +use sp1_primitives::consts::WORD_SIZE; use sp1_recursion_core::{air::RecursionPublicValues, stark::config::BabyBearPoseidon2Outer}; -use sp1_recursion_gnark_ffi::{PlonkBn254Proof, PlonkBn254Prover}; +use sp1_recursion_gnark_ffi::{ + Groth16Bn254Proof, Groth16Bn254Prover, PlonkBn254Proof, PlonkBn254Prover, +}; +use sp1_stark::{ + air::{PublicValues, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}, + baby_bear_poseidon2::BabyBearPoseidon2, + MachineProof, MachineProver, MachineVerificationError, StarkGenericConfig, Word, +}; use thiserror::Error; -use crate::components::SP1ProverComponents; use crate::{ - CoreSC, HashableKey, OuterSC, SP1CoreProofData, SP1Prover, SP1ReduceProof, SP1VerifyingKey, + components::SP1ProverComponents, CoreSC, HashableKey, OuterSC, SP1CoreProofData, SP1Prover, + SP1ReduceProof, SP1VerifyingKey, }; #[derive(Error, Debug)] @@ -35,6 +35,18 @@ pub enum PlonkVerificationError { InvalidPublicValues, } +#[derive(Error, Debug)] +pub enum Groth16VerificationError { + #[error( + "the verifying key does not match the inner groth16 bn254 proof's committed verifying key" + )] + InvalidVerificationKey, + #[error( + "the public values in the sp1 proof do not match the public values in the inner groth16 bn254 proof" + )] + InvalidPublicValues, +} + impl SP1Prover { /// Verify a core proof by verifying the shards, verifying lookup bus, verifying that the /// shards are contiguous and complete. @@ -59,9 +71,7 @@ impl SP1Prover { if shard_proof.contains_cpu() { let log_degree_cpu = shard_proof.log_degree_cpu(); if log_degree_cpu > MAX_CPU_LOG_DEGREE { - return Err(MachineVerificationError::CpuLogDegreeTooLarge( - log_degree_cpu, - )); + return Err(MachineVerificationError::CpuLogDegreeTooLarge(log_degree_cpu)); } } } @@ -169,10 +179,14 @@ impl SP1Prover { // - `previous_finalize_addr_bits` should be zero. // // Transition: - // - For all shards, `previous_init_addr_bits` should equal `last_init_addr_bits` of the previous shard. - // - For all shards, `previous_finalize_addr_bits` should equal `last_finalize_addr_bits` of the previous shard. - // - For shards without "MemoryInit", `previous_init_addr_bits` should equal `last_init_addr_bits`. - // - For shards without "MemoryFinalize", `previous_finalize_addr_bits` should equal `last_finalize_addr_bits`. + // - For all shards, `previous_init_addr_bits` should equal `last_init_addr_bits` of the + // previous shard. + // - For all shards, `previous_finalize_addr_bits` should equal `last_finalize_addr_bits` of + // the previous shard. + // - For shards without "MemoryInit", `previous_init_addr_bits` should equal + // `last_init_addr_bits`. + // - For shards without "MemoryFinalize", `previous_finalize_addr_bits` should equal + // `last_finalize_addr_bits`. let mut last_init_addr_bits_prev = [BabyBear::zero(); 32]; let mut last_finalize_addr_bits_prev = [BabyBear::zero(); 32]; for shard_proof in proof.0.iter() { @@ -213,11 +227,13 @@ impl SP1Prover { // Transition: // - If `commited_value_digest_prev` is not zero, then `committed_value_digest` should equal // `commited_value_digest_prev`. Otherwise, `committed_value_digest` should equal zero. - // - If `deferred_proofs_digest_prev` is not zero, then `deferred_proofs_digest` should equal + // - If `deferred_proofs_digest_prev` is not zero, then `deferred_proofs_digest` should + // equal // `deferred_proofs_digest_prev`. Otherwise, `deferred_proofs_digest` should equal zero. // - If it's not a shard with "CPU", then `commited_value_digest` should not change from the // previous shard. - // - If it's not a shard with "CPU", then `deferred_proofs_digest` should not change from the + // - If it's not a shard with "CPU", then `deferred_proofs_digest` should not change from + // the // previous shard. let zero_commited_value_digest = [Word([BabyBear::zero(); WORD_SIZE]); PV_DIGEST_NUM_WORDS]; let zero_deferred_proofs_digest = [BabyBear::zero(); POSEIDON_NUM_WORDS]; @@ -262,12 +278,8 @@ impl SP1Prover { // Verify the shard proof. let mut challenger = self.core_prover.config().challenger(); - let machine_proof = MachineProof { - shard_proofs: proof.0.to_vec(), - }; - self.core_prover - .machine() - .verify(&vk.vk, &machine_proof, &mut challenger)?; + let machine_proof = MachineProof { shard_proofs: proof.0.to_vec() }; + self.core_prover.machine().verify(&vk.vk, &machine_proof, &mut challenger)?; Ok(()) } @@ -279,9 +291,7 @@ impl SP1Prover { vk: &SP1VerifyingKey, ) -> Result<(), MachineVerificationError> { let mut challenger = self.compress_prover.config().challenger(); - let machine_proof = MachineProof { - shard_proofs: vec![proof.proof.clone()], - }; + let machine_proof = MachineProof { shard_proofs: vec![proof.proof.clone()] }; self.compress_prover.machine().verify( self.compress_vk(), &machine_proof, @@ -292,19 +302,16 @@ impl SP1Prover { let public_values: &RecursionPublicValues<_> = proof.proof.public_values.as_slice().borrow(); - // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully reduced. + // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully + // reduced. if public_values.is_complete != BabyBear::one() { - return Err(MachineVerificationError::InvalidPublicValues( - "is_complete is not 1", - )); + return Err(MachineVerificationError::InvalidPublicValues("is_complete is not 1")); } // Verify that the proof is for the sp1 vkey we are expecting. let vkey_hash = vk.hash_babybear(); if public_values.sp1_vk_digest != vkey_hash { - return Err(MachineVerificationError::InvalidPublicValues( - "sp1 vk hash mismatch", - )); + return Err(MachineVerificationError::InvalidPublicValues("sp1 vk hash mismatch")); } // Verify that the reduce program is the one we are expecting. @@ -325,30 +332,23 @@ impl SP1Prover { vk: &SP1VerifyingKey, ) -> Result<(), MachineVerificationError> { let mut challenger = self.shrink_prover.config().challenger(); - let machine_proof = MachineProof { - shard_proofs: vec![proof.proof.clone()], - }; - self.shrink_prover - .machine() - .verify(self.shrink_vk(), &machine_proof, &mut challenger)?; + let machine_proof = MachineProof { shard_proofs: vec![proof.proof.clone()] }; + self.shrink_prover.machine().verify(self.shrink_vk(), &machine_proof, &mut challenger)?; // Validate public values let public_values: &RecursionPublicValues<_> = proof.proof.public_values.as_slice().borrow(); - // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully reduced. + // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully + // reduced. if public_values.is_complete != BabyBear::one() { - return Err(MachineVerificationError::InvalidPublicValues( - "is_complete is not 1", - )); + return Err(MachineVerificationError::InvalidPublicValues("is_complete is not 1")); } // Verify that the proof is for the sp1 vkey we are expecting. let vkey_hash = vk.hash_babybear(); if public_values.sp1_vk_digest != vkey_hash { - return Err(MachineVerificationError::InvalidPublicValues( - "sp1 vk hash mismatch", - )); + return Err(MachineVerificationError::InvalidPublicValues("sp1 vk hash mismatch")); } Ok(()) @@ -361,30 +361,23 @@ impl SP1Prover { vk: &SP1VerifyingKey, ) -> Result<(), MachineVerificationError> { let mut challenger = self.wrap_prover.config().challenger(); - let machine_proof = MachineProof { - shard_proofs: vec![proof.proof.clone()], - }; - self.wrap_prover - .machine() - .verify(self.wrap_vk(), &machine_proof, &mut challenger)?; + let machine_proof = MachineProof { shard_proofs: vec![proof.proof.clone()] }; + self.wrap_prover.machine().verify(self.wrap_vk(), &machine_proof, &mut challenger)?; // Validate public values let public_values: &RecursionPublicValues<_> = proof.proof.public_values.as_slice().borrow(); - // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully reduced. + // `is_complete` should be 1. In the reduce program, this ensures that the proof is fully + // reduced. if public_values.is_complete != BabyBear::one() { - return Err(MachineVerificationError::InvalidPublicValues( - "is_complete is not 1", - )); + return Err(MachineVerificationError::InvalidPublicValues("is_complete is not 1")); } // Verify that the proof is for the sp1 vkey we are expecting. let vkey_hash = vk.hash_babybear(); if public_values.sp1_vk_digest != vkey_hash { - return Err(MachineVerificationError::InvalidPublicValues( - "sp1 vk hash mismatch", - )); + return Err(MachineVerificationError::InvalidPublicValues("sp1 vk hash mismatch")); } Ok(()) @@ -410,9 +403,31 @@ impl SP1Prover { Ok(()) } + + /// Verifies a Groth16 proof using the circuit artifacts in the build directory. + pub fn verify_groth16_bn254( + &self, + proof: &Groth16Bn254Proof, + vk: &SP1VerifyingKey, + public_values: &SP1PublicValues, + build_dir: &Path, + ) -> Result<()> { + let prover = Groth16Bn254Prover::new(); + + let vkey_hash = BigUint::from_str(&proof.public_inputs[0])?; + let committed_values_digest = BigUint::from_str(&proof.public_inputs[1])?; + + // Verify the proof with the corresponding public inputs. + prover.verify(proof, &vkey_hash, &committed_values_digest, build_dir); + + verify_groth16_bn254_public_inputs(vk, public_values, &proof.public_inputs)?; + + Ok(()) + } } -/// Verify the vk_hash and public_values_hash in the public inputs of the PlonkBn254Proof match the expected values. +/// Verify the vk_hash and public_values_hash in the public inputs of the PlonkBn254Proof match the +/// expected values. pub fn verify_plonk_bn254_public_inputs( vk: &SP1VerifyingKey, public_values: &SP1PublicValues, @@ -434,11 +449,34 @@ pub fn verify_plonk_bn254_public_inputs( Ok(()) } +/// Verify the vk_hash and public_values_hash in the public inputs of the Groth16Bn254Proof match +/// the expected values. +pub fn verify_groth16_bn254_public_inputs( + vk: &SP1VerifyingKey, + public_values: &SP1PublicValues, + groth16_bn254_public_inputs: &[String], +) -> Result<()> { + let expected_vk_hash = BigUint::from_str(&groth16_bn254_public_inputs[0])?; + let expected_public_values_hash = BigUint::from_str(&groth16_bn254_public_inputs[1])?; + + let vk_hash = vk.hash_bn254().as_canonical_biguint(); + if vk_hash != expected_vk_hash { + return Err(Groth16VerificationError::InvalidVerificationKey.into()); + } + + let public_values_hash = public_values.hash(); + if public_values_hash != expected_public_values_hash { + return Err(Groth16VerificationError::InvalidPublicValues.into()); + } + + Ok(()) +} + impl SubproofVerifier for &SP1Prover { fn verify_deferred_proof( &self, - proof: &sp1_core::stark::ShardProof, - vk: &sp1_core::stark::StarkVerifyingKey, + proof: &sp1_stark::ShardProof, + vk: &sp1_stark::StarkVerifyingKey, vk_hash: [u32; 8], committed_value_digest: [u32; 8], ) -> Result<(), MachineVerificationError> { @@ -450,9 +488,7 @@ impl SubproofVerifier for &SP1Prover { } // Check that proof is valid. self.verify_compressed( - &SP1ReduceProof { - proof: proof.clone(), - }, + &SP1ReduceProof { proof: proof.clone() }, &SP1VerifyingKey { vk: vk.clone() }, )?; // Check that the committed value digest matches the one from syscall diff --git a/crates/recursion/README.md b/crates/recursion/README.md new file mode 100644 index 0000000000..7eef01070a --- /dev/null +++ b/crates/recursion/README.md @@ -0,0 +1,10 @@ +# SP1 Recursion + + +## Debugging recursion programs +The recursion programs are executed in the recursion runtime. In case of a panic in the recursion +runtime, rust will panic with a `TRAP` error. In order to get detailed information about the panic, +with a backtrace, compile the test with the evvironment variables: +```bash +RUST_BACKTRACE=1 RUSTFLAGS="-g" SP1_DEBUG=true +``` \ No newline at end of file diff --git a/crates/recursion/circuit-v2/CHANGELOG.md b/crates/recursion/circuit-v2/CHANGELOG.md new file mode 100644 index 0000000000..fe22843ca1 --- /dev/null +++ b/crates/recursion/circuit-v2/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-recursion-circuit-v2-v1.2.0-rc1) - 2024-08-23 + +### Added + +- unify inner and outer witnesses in recursion circuit ([#1374](https://github.com/succinctlabs/sp1/pull/1374)) +- plonk in new circuit ([#1364](https://github.com/succinctlabs/sp1/pull/1364)) + +### Other + +- use crate `vec_map`, box large `Instruction` variants ([#1360](https://github.com/succinctlabs/sp1/pull/1360)) +- merge dev into experimental pt 2 ([#1341](https://github.com/succinctlabs/sp1/pull/1341)) +- add circuit v2 +- resolve merge conflicts between dev and experimental diff --git a/crates/recursion/circuit-v2/Cargo.toml b/crates/recursion/circuit-v2/Cargo.toml new file mode 100644 index 0000000000..a2be9881b7 --- /dev/null +++ b/crates/recursion/circuit-v2/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "sp1-recursion-circuit-v2" +description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." +readme = "../../../README.md" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } + +[dependencies] +p3-air = { workspace = true } +p3-field = { workspace = true } +p3-commit = { workspace = true } +p3-fri = { workspace = true } +p3-matrix = { workspace = true } +p3-util = { workspace = true } +p3-maybe-rayon = { workspace = true } +p3-symmetric = { workspace = true } +p3-challenger = { workspace = true } +p3-dft = { workspace = true } +p3-merkle-tree = { workspace = true } +p3-poseidon2 = { workspace = true } +p3-bn254-fr = { workspace = true } +p3-baby-bear = { workspace = true } + +sp1-core-machine = { workspace = true } +sp1-core-executor = { workspace = true } +sp1-stark = { workspace = true } + +# todo: remove this dependency once everything is migrated. +sp1-recursion-program = { workspace = true } + +sp1-recursion-core-v2 = { workspace = true } +sp1-recursion-derive = { workspace = true } +sp1-recursion-compiler = { workspace = true } +sp1-primitives = { workspace = true } +sp1-recursion-gnark-ffi = { workspace = true } +sp1-recursion-circuit = { workspace = true } + +itertools = "0.13.0" +serde = { version = "1.0.204", features = ["derive"] } +bincode = "1.3.3" +rand = "0.8.5" +tracing = "0.1.40" +hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] } +stacker = "0.1" + +[dev-dependencies] +sp1-core-executor = { workspace = true, features = ["programs"] } +ff = { version = "0.13", features = ["derive", "derive_bits"] } +p3-challenger = { workspace = true } +p3-symmetric = { workspace = true } +p3-dft = { workspace = true } +p3-merkle-tree = { workspace = true } +p3-poseidon2 = { workspace = true } +zkhash = "0.2.0" +rand = "0.8.5" + +[features] +native-gnark = ["sp1-recursion-gnark-ffi/native"] +export-tests = [] diff --git a/crates/recursion/circuit-v2/scripts/circuit_architecture_sweep.rs b/crates/recursion/circuit-v2/scripts/circuit_architecture_sweep.rs new file mode 100644 index 0000000000..0e76784618 --- /dev/null +++ b/crates/recursion/circuit-v2/scripts/circuit_architecture_sweep.rs @@ -0,0 +1,66 @@ +//! Sweeps end-to-end prover performance across a wide range of parameters for the Plonk circuit builder. + +use p3_baby_bear::BabyBear; + +use sp1_core::{stark::StarkMachine, utils::log2_strict_usize}; +use sp1_recursion_circuit_v2::build_wrap_v2::{machine_with_all_chips, test_machine}; +use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; +use sp1_recursion_core_v2::machine::RecursionAir; + +type SC = BabyBearPoseidon2Outer; + +fn machine_with_dummy( + log_height: usize, +) -> StarkMachine> { + let config = SC::new_with_log_blowup(log2_strict_usize(DEGREE - 1)); + RecursionAir::::dummy_machine(config, log_height) +} + +fn main() { + // Test the performance of the full architecture with different degrees. + let machine_maker_3 = || machine_with_all_chips::<3>(16, 16, 16); + let machine_maker_5 = || machine_with_all_chips::<5>(16, 16, 16); + let machine_maker_9 = || machine_with_all_chips::<9>(16, 16, 16); + let machine_maker_17 = || machine_with_all_chips::<17>(16, 16, 16); + test_machine(machine_maker_3); + test_machine(machine_maker_5); + test_machine(machine_maker_9); + test_machine(machine_maker_17); + + // Test the performance of the machine with the full architecture for different numbers of rows + // in the precompiles. Degree is set to 9. + let machine_maker = |i| machine_with_all_chips::<9>(i, i, i); + for i in 1..=5 { + test_machine(|| machine_maker(i)); + } + + // Test the performance of the dummy machine for different numbers of columns in the dummy table. + // Degree is kept fixed at 9. + test_machine(|| machine_with_dummy::<9, 1>(16)); + test_machine(|| machine_with_dummy::<9, 50>(16)); + test_machine(|| machine_with_dummy::<9, 100>(16)); + test_machine(|| machine_with_dummy::<9, 150>(16)); + test_machine(|| machine_with_dummy::<9, 200>(16)); + test_machine(|| machine_with_dummy::<9, 250>(16)); + test_machine(|| machine_with_dummy::<9, 300>(16)); + test_machine(|| machine_with_dummy::<9, 350>(16)); + test_machine(|| machine_with_dummy::<9, 400>(16)); + test_machine(|| machine_with_dummy::<9, 450>(16)); + test_machine(|| machine_with_dummy::<9, 500>(16)); + test_machine(|| machine_with_dummy::<9, 550>(16)); + test_machine(|| machine_with_dummy::<9, 600>(16)); + test_machine(|| machine_with_dummy::<9, 650>(16)); + test_machine(|| machine_with_dummy::<9, 700>(16)); + test_machine(|| machine_with_dummy::<9, 750>(16)); + + // Test the performance of the dummy machine for different heights of the dummy table. + for i in 4..=7 { + test_machine(|| machine_with_dummy::<9, 1>(i)); + } + + // Change the degree for the dummy table, keeping other parameters fixed. + test_machine(|| machine_with_dummy::<3, 500>(16)); + test_machine(|| machine_with_dummy::<5, 500>(16)); + test_machine(|| machine_with_dummy::<9, 500>(16)); + test_machine(|| machine_with_dummy::<17, 500>(16)); +} diff --git a/crates/recursion/circuit-v2/src/build_wrap_v2.rs b/crates/recursion/circuit-v2/src/build_wrap_v2.rs new file mode 100644 index 0000000000..f5cc231baa --- /dev/null +++ b/crates/recursion/circuit-v2/src/build_wrap_v2.rs @@ -0,0 +1,517 @@ +use std::borrow::Borrow; + +use itertools::Itertools; +use p3_baby_bear::BabyBear; +use p3_bn254_fr::Bn254Fr; +use p3_field::AbstractField; +use p3_fri::TwoAdicFriPcsProof; +use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::{Constraint, ConstraintCompiler}, + ir::{Builder, Config, Ext, Felt, SymbolicExt, Var}, +}; +use sp1_recursion_core_v2::{ + air::RecursionPublicValues, + machine::RecursionAir, + stark::config::{ + BabyBearPoseidon2Outer, OuterChallenge, OuterChallengeMmcs, OuterFriProof, OuterVal, + OuterValMmcs, + }, +}; +use sp1_stark::{ + AirOpenedValues, ChipOpenedValues, ShardCommitment, ShardOpenedValues, ShardProof, + StarkMachine, StarkVerifyingKey, +}; + +use crate::{ + challenger::{CanObserveVariable, MultiField32ChallengerVariable}, + stark::{ShardProofVariable, StarkVerifier}, + utils::{felt_bytes_to_bn254_var, felts_to_bn254_var, words_to_bytes}, + witness::Witnessable, + BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, + TwoAdicPcsProofVariable, VerifyingKeyVariable, +}; + +pub const DIGEST_SIZE: usize = 1; + +type OuterSC = BabyBearPoseidon2Outer; +type OuterC = OuterConfig; +type OuterDigestVariable = [Var<::N>; DIGEST_SIZE]; + +/// A function to build the circuit for the final wrap layer using the architecture of core-v2. +/// +/// For now, the witnessing logic is not implemented and we just witness via constant proof variables. +pub fn build_wrap_circuit_v2( + wrap_vk: &StarkVerifyingKey, + template_proof: ShardProof, + outer_machine: StarkMachine>, +) -> Vec +where +{ + let mut builder = Builder::::default(); + let mut challenger = MultiField32ChallengerVariable::new(&mut builder); + + let preprocessed_commit_val: [Bn254Fr; 1] = wrap_vk.commit.into(); + let preprocessed_commit: OuterDigestVariable = [builder.eval(preprocessed_commit_val[0])]; + challenger.observe_commitment(&mut builder, preprocessed_commit); + let pc_start = builder.eval(wrap_vk.pc_start); + challenger.observe(&mut builder, pc_start); + + // let mut witness = OuterWitness::default(); + // template_proof.write(&mut witness); + + let proof = template_proof.read(&mut builder); + // let proof = const_shard_proof(&mut builder, &template_proof); + + let commited_values_digest = builder.constant(::N::zero()); + builder.commit_commited_values_digest_circuit(commited_values_digest); + let vkey_hash = builder.constant(::N::zero()); + builder.commit_vkey_hash_circuit(vkey_hash); + + // Validate public values + // let mut pv_elements = Vec::new(); + // for i in 0..PROOF_MAX_NUM_PVS { + // let element = builder.get(&proof.public_values, i); + // pv_elements.push(element); + // } + + let pv: &RecursionPublicValues<_> = proof.public_values.as_slice().borrow(); + + // TODO: Add back. + // let one_felt: Felt<_> = builder.constant(BabyBear::one()); + // // Proof must be complete. In the reduce program, this will ensure that the SP1 proof has + // // been fully accumulated. + // builder.assert_felt_eq(pv.is_complete, one_felt); + + // Convert pv.sp1_vk_digest into Bn254 + let pv_vkey_hash = felts_to_bn254_var(&mut builder, &pv.sp1_vk_digest); + // Vkey hash must match the witnessed commited_values_digest that we are committing to. + builder.assert_var_eq(pv_vkey_hash, vkey_hash); + + // Convert pv.committed_value_digest into Bn254 + let pv_committed_values_digest_bytes: [Felt<_>; 32] = + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); + let pv_committed_values_digest: Var<_> = + felt_bytes_to_bn254_var(&mut builder, &pv_committed_values_digest_bytes); + + // // Committed values digest must match the witnessed one that we are committing to. + builder.assert_var_eq(pv_committed_values_digest, commited_values_digest); + + let ShardCommitment { main_commit, .. } = &proof.commitment; + challenger.observe_commitment(&mut builder, *main_commit); + + challenger.observe_slice(&mut builder, proof.clone().public_values); + + let StarkVerifyingKey { commit, pc_start, chip_information, chip_ordering } = wrap_vk; + + let wrap_vk = VerifyingKeyVariable { + commitment: commit + .into_iter() + .map(|elem| builder.eval(elem)) + .collect_vec() + .try_into() + .unwrap(), + pc_start: builder.eval(*pc_start), + chip_information: chip_information.clone(), + chip_ordering: chip_ordering.clone(), + }; + + StarkVerifier::::verify_shard( + &mut builder, + &wrap_vk, + &outer_machine, + &mut challenger.clone(), + &proof, + ); + + let zero_ext: Ext<_, _> = builder.constant(::EF::zero()); + let cumulative_sum: Ext<_, _> = builder.eval(zero_ext); + for chip in proof.opened_values.chips { + builder.assign(cumulative_sum, cumulative_sum + chip.cumulative_sum); + } + builder.assert_ext_eq(cumulative_sum, zero_ext); + + // TODO: Add back. + // Verify the public values digest. + // let calculated_digest = + // builder.p2_circuit_babybear_hash(&proof.public_values[0..NUM_PV_ELMS_TO_HASH]); + // let expected_digest = pv.digest; + // for (calculated_elm, expected_elm) in calculated_digest.iter().zip(expected_digest.iter()) { + // builder.assert_felt_eq(*expected_elm, *calculated_elm); + // } + + let mut backend = ConstraintCompiler::::default(); + backend.emit(builder.operations) +} + +/// A utility function to convert a `ShardProof` into a `ShardProofVariable`. Should be replaced by +/// more refined witness generation. +pub fn const_shard_proof( + builder: &mut Builder, + proof: &ShardProof, +) -> ShardProofVariable { + let opening_proof = const_two_adic_pcs_proof(builder, proof.opening_proof.clone()); + let opened_values = proof + .opened_values + .chips + .iter() + .map(|chip| { + let ChipOpenedValues { + preprocessed, + main, + permutation, + quotient, + cumulative_sum, + log_degree, + } = chip; + let AirOpenedValues { local: prepr_local, next: prepr_next } = preprocessed; + let AirOpenedValues { local: main_local, next: main_next } = main; + let AirOpenedValues { local: perm_local, next: perm_next } = permutation; + + let quotient = + quotient.iter().map(|q| q.iter().map(|x| builder.constant(*x)).collect()).collect(); + let cumulative_sum = builder.constant(*cumulative_sum); + + let preprocessed = AirOpenedValues { + local: prepr_local.iter().map(|x| builder.constant(*x)).collect(), + next: prepr_next.iter().map(|x| builder.constant(*x)).collect(), + }; + + let main = AirOpenedValues { + local: main_local.iter().map(|x| builder.constant(*x)).collect(), + next: main_next.iter().map(|x| builder.constant(*x)).collect(), + }; + + let permutation = AirOpenedValues { + local: perm_local.iter().map(|x| builder.constant(*x)).collect(), + next: perm_next.iter().map(|x| builder.constant(*x)).collect(), + }; + + ChipOpenedValues { + preprocessed, + main, + permutation, + quotient, + cumulative_sum, + log_degree: *log_degree, + } + }) + .collect(); + let opened_values = ShardOpenedValues { chips: opened_values }; + let ShardCommitment { main_commit, permutation_commit, quotient_commit } = proof.commitment; + let main_commit: [Bn254Fr; 1] = main_commit.into(); + let permutation_commit: [Bn254Fr; 1] = permutation_commit.into(); + let quotient_commit: [Bn254Fr; 1] = quotient_commit.into(); + + let main_commit = core::array::from_fn(|i| builder.eval(main_commit[i])); + let permutation_commit = core::array::from_fn(|i| builder.eval(permutation_commit[i])); + let quotient_commit = core::array::from_fn(|i| builder.eval(quotient_commit[i])); + + let commitment = ShardCommitment { main_commit, permutation_commit, quotient_commit }; + ShardProofVariable { + commitment, + public_values: proof.public_values.iter().map(|x| builder.constant(*x)).collect(), + opened_values, + opening_proof, + chip_ordering: proof.chip_ordering.clone(), + } +} + +type C = OuterConfig; +type SC = BabyBearPoseidon2Outer; +type N = ::N; + +// Copy-paste from InnerCircuit implementation, changing generic parameters. +fn const_fri_proof( + builder: &mut Builder, + fri_proof: OuterFriProof, +) -> FriProofVariable { + // Set the commit phase commits. + let commit_phase_commits = fri_proof + .commit_phase_commits + .iter() + .map(|commit| { + let commit: [N; DIGEST_SIZE] = (*commit).into(); + commit.map(|x| builder.eval(x)) + }) + .collect::>(); + + // Set the query proofs. + let query_proofs = fri_proof + .query_proofs + .iter() + .map(|query_proof| { + let commit_phase_openings = query_proof + .commit_phase_openings + .iter() + .map(|commit_phase_opening| { + let sibling_value = + builder.eval(SymbolicExt::from_f(commit_phase_opening.sibling_value)); + let opening_proof = commit_phase_opening + .opening_proof + .iter() + .map(|sibling| sibling.map(|x| builder.eval(x))) + .collect::>(); + FriCommitPhaseProofStepVariable { sibling_value, opening_proof } + }) + .collect::>(); + FriQueryProofVariable { commit_phase_openings } + }) + .collect::>(); + + // Initialize the FRI proof variable. + FriProofVariable { + commit_phase_commits, + query_proofs, + final_poly: builder.eval(SymbolicExt::from_f(fri_proof.final_poly)), + pow_witness: builder.eval(fri_proof.pow_witness), + } +} + +pub fn const_two_adic_pcs_proof( + builder: &mut Builder, + proof: TwoAdicFriPcsProof, +) -> TwoAdicPcsProofVariable { + let fri_proof = const_fri_proof(builder, proof.fri_proof); + let query_openings = proof + .query_openings + .iter() + .map(|query_opening| { + query_opening + .iter() + .map(|opening| BatchOpeningVariable { + opened_values: opening + .opened_values + .iter() + .map(|opened_value| { + opened_value + .iter() + .map(|value| vec![builder.eval::, _>(*value)]) + .collect::>() + }) + .collect::>(), + opening_proof: opening + .opening_proof + .iter() + .map(|opening_proof| opening_proof.map(|x| builder.eval(x))) + .collect::>(), + }) + .collect::>() + }) + .collect::>(); + TwoAdicPcsProofVariable { fri_proof, query_openings } +} +#[cfg(test)] +pub mod tests { + + use std::{borrow::Borrow, iter::once, sync::Arc}; + + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_challenger::{CanObserve, FieldChallenger}; + use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; + use p3_field::{extension::BinomialExtensionField, AbstractField}; + use p3_matrix::dense::RowMajorMatrix; + use rand::{rngs::StdRng, SeedableRng}; + use sp1_core_machine::utils::{log2_strict_usize, run_test_machine, setup_logger}; + use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::ConstraintCompiler, + ir::{Builder, Config, Ext, SymbolicExt}, + }; + use sp1_recursion_core_v2::{ + air::RecursionPublicValues, + instruction as instr, + machine::RecursionAir, + stark::config::{ + outer_fri_config, outer_perm, BabyBearPoseidon2Outer, OuterChallenge, OuterChallenger, + OuterCompress, OuterDft, OuterHash, OuterPcs, OuterVal, OuterValMmcs, + }, + BaseAluOpcode, MemAccessKind, RecursionProgram, Runtime, + }; + use sp1_recursion_gnark_ffi::{Groth16Bn254Prover, PlonkBn254Prover}; + use sp1_stark::{BabyBearPoseidon2Inner, StarkMachine}; + + use crate::{ + challenger::CanObserveVariable, + fri::verify_two_adic_pcs, + hash::BN254_DIGEST_SIZE, + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + witness::{OuterWitness, Witnessable}, + Digest, TwoAdicPcsMatsVariable, TwoAdicPcsRoundVariable, + }; + + use super::{build_wrap_circuit_v2, const_two_adic_pcs_proof}; + + fn test_machine(machine_maker: F) + where + F: Fn() -> StarkMachine>, + { + setup_logger(); + let n = 10; + // Fibonacci(n) + let instructions = once(instr::mem(MemAccessKind::Write, 1, 0, 0)) + .chain(once(instr::mem(MemAccessKind::Write, 2, 1, 1))) + .chain((2..=n).map(|i| instr::base_alu(BaseAluOpcode::AddF, 2, i, i - 2, i - 1))) + .chain(once(instr::mem(MemAccessKind::Read, 1, n - 1, 34))) + .chain(once(instr::mem(MemAccessKind::Read, 2, n, 55))) + .collect::>(); + + let machine = machine_maker(); + let program = RecursionProgram { instructions, ..Default::default() }; + let mut runtime = + Runtime::, DiffusionMatrixBabyBear>::new( + Arc::new(program.clone()), + BabyBearPoseidon2Inner::new().perm, + ); + runtime.run().unwrap(); + + let (pk, vk) = machine.setup(&program); + let result = run_test_machine(vec![runtime.record], machine, pk, vk.clone()).unwrap(); + + let machine = machine_maker(); + let constraints = + build_wrap_circuit_v2::(&vk, result.shard_proofs[0].clone(), machine); + + let pv: &RecursionPublicValues<_> = + result.shard_proofs[0].public_values.as_slice().borrow(); + let vkey_hash = babybears_to_bn254(&pv.sp1_vk_digest); + let committed_values_digest_bytes: [BabyBear; 32] = + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); + let committed_values_digest = babybear_bytes_to_bn254(&committed_values_digest_bytes); + + // Build the witness. + let mut witness = OuterWitness::default(); + result.shard_proofs[0].write(&mut witness); + witness.write_commited_values_digest(committed_values_digest); + witness.write_vkey_hash(vkey_hash); + + PlonkBn254Prover::test::(constraints.clone(), witness.clone()); + Groth16Bn254Prover::test::(constraints, witness); + } + + pub fn machine_with_all_chips( + log_erbl_rows: usize, + log_p2_rows: usize, + log_frifold_rows: usize, + ) -> StarkMachine> { + let config = SC::new_with_log_blowup(log2_strict_usize(DEGREE - 1)); + RecursionAir::::machine_with_padding( + config, + log_frifold_rows, + log_p2_rows, + log_erbl_rows, + ) + } + + #[test] + fn test_build_wrap() { + let machine_maker = || machine_with_all_chips::<17>(3, 3, 3); + test_machine(machine_maker); + } + type C = OuterConfig; + type SC = BabyBearPoseidon2Outer; + + #[allow(clippy::type_complexity)] + pub fn const_two_adic_pcs_rounds( + builder: &mut Builder, + commit: [::N; BN254_DIGEST_SIZE], + os: Vec<(TwoAdicMultiplicativeCoset, Vec<(OuterChallenge, Vec)>)>, + ) -> (Digest, Vec>) { + let commit: Digest = commit.map(|x| builder.eval(x)); + + let mut domains_points_and_opens = Vec::new(); + for (domain, poly) in os.into_iter() { + let points: Vec> = + poly.iter().map(|(p, _)| builder.eval(SymbolicExt::from_f(*p))).collect::>(); + let values: Vec>> = poly + .iter() + .map(|(_, v)| { + v.clone() + .iter() + .map(|t| builder.eval(SymbolicExt::from_f(*t))) + .collect::>() + }) + .collect::>(); + let domain_points_and_values = TwoAdicPcsMatsVariable { domain, points, values }; + domains_points_and_opens.push(domain_points_and_values); + } + + (commit, vec![TwoAdicPcsRoundVariable { batch_commit: commit, domains_points_and_opens }]) + } + + #[test] + fn test_verify_two_adic_pcs_outer() { + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let log_degrees = &[19, 19]; + let perm = outer_perm(); + let mut fri_config = outer_fri_config(); + + // Lower blowup factor for testing. + fri_config.log_blowup = 2; + let hash = OuterHash::new(perm.clone()).unwrap(); + let compress = OuterCompress::new(perm.clone()); + let val_mmcs = OuterValMmcs::new(hash, compress); + let dft = OuterDft {}; + let pcs: OuterPcs = + OuterPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); + + // Generate proof. + let domains_and_polys = log_degrees + .iter() + .map(|&d| { + ( + >::natural_domain_for_degree( + &pcs, + 1 << d, + ), + RowMajorMatrix::::rand(&mut rng, 1 << d, 100), + ) + }) + .collect::>(); + let (commit, data) = >::commit( + &pcs, + domains_and_polys.clone(), + ); + let mut challenger = OuterChallenger::new(perm.clone()).unwrap(); + challenger.observe(commit); + let zeta = challenger.sample_ext_element::(); + let points = domains_and_polys.iter().map(|_| vec![zeta]).collect::>(); + let (opening, proof) = pcs.open(vec![(&data, points)], &mut challenger); + + // Verify proof. + let mut challenger = OuterChallenger::new(perm.clone()).unwrap(); + challenger.observe(commit); + let x1 = challenger.sample_ext_element::(); + let os = domains_and_polys + .iter() + .zip(&opening[0]) + .map(|((domain, _), mat_openings)| (*domain, vec![(zeta, mat_openings[0].clone())])) + .collect::>(); + pcs.verify(vec![(commit, os.clone())], &proof, &mut challenger).unwrap(); + + // Define circuit. + let mut builder = Builder::::default(); + let mut config = outer_fri_config(); + + // Lower blowup factor for testing. + config.log_blowup = 2; + let proof = const_two_adic_pcs_proof(&mut builder, proof); + let (commit, rounds) = const_two_adic_pcs_rounds(&mut builder, commit.into(), os); + let mut challenger = crate::challenger::MultiField32ChallengerVariable::new(&mut builder); + challenger.observe_slice(&mut builder, commit); + let x2 = challenger.sample_ext(&mut builder); + let x1: Ext<_, _> = builder.constant(x1); + builder.assert_ext_eq(x1, x2); + verify_two_adic_pcs::<_, BabyBearPoseidon2Outer>( + &mut builder, + &config, + &proof, + &mut challenger, + rounds, + ); + let mut backend = ConstraintCompiler::::default(); + let constraints = backend.emit(builder.operations); + let witness = OuterWitness::default(); + PlonkBn254Prover::test::(constraints, witness); + } +} diff --git a/crates/recursion/circuit-v2/src/challenger.rs b/crates/recursion/circuit-v2/src/challenger.rs new file mode 100644 index 0000000000..2ea066920d --- /dev/null +++ b/crates/recursion/circuit-v2/src/challenger.rs @@ -0,0 +1,650 @@ +use p3_field::{AbstractField, Field}; +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + ir::{DslIr, Var}, + prelude::{Builder, Config, Ext, Felt}, +}; +use sp1_recursion_core_v2::{ + air::ChallengerPublicValues, + runtime::{HASH_RATE, PERMUTATION_WIDTH}, + NUM_BITS, +}; + +// Constants for the Multifield challenger. +pub const SPONGE_SIZE: usize = 3; +pub const DIGEST_SIZE: usize = 1; +pub const RATE: usize = 16; + +// use crate::{DigestVariable, VerifyingKeyVariable}; + +pub trait CanCopyChallenger { + fn copy(&self, builder: &mut Builder) -> Self; +} +/// Reference: [p3_challenger::CanObserve]. +pub trait CanObserveVariable { + fn observe(&mut self, builder: &mut Builder, value: V); + + fn observe_slice(&mut self, builder: &mut Builder, values: impl IntoIterator) { + for value in values { + self.observe(builder, value); + } + } +} + +pub trait CanSampleVariable { + fn sample(&mut self, builder: &mut Builder) -> V; +} + +/// Reference: [p3_challenger::FieldChallenger]. +pub trait FieldChallengerVariable: + CanObserveVariable> + CanSampleVariable> + CanSampleBitsVariable +{ + fn sample_ext(&mut self, builder: &mut Builder) -> Ext; + + fn check_witness(&mut self, builder: &mut Builder, nb_bits: usize, witness: Felt); + + fn duplexing(&mut self, builder: &mut Builder); +} + +pub trait CanSampleBitsVariable { + fn sample_bits(&mut self, builder: &mut Builder, nb_bits: usize) -> Vec; +} + +/// Reference: [p3_challenger::DuplexChallenger] +#[derive(Clone)] +pub struct DuplexChallengerVariable { + pub sponge_state: [Felt; PERMUTATION_WIDTH], + pub input_buffer: Vec>, + pub output_buffer: Vec>, +} + +impl DuplexChallengerVariable { + /// Creates a new duplex challenger with the default state. + pub fn new(builder: &mut Builder) -> Self { + DuplexChallengerVariable:: { + sponge_state: core::array::from_fn(|_| builder.eval(C::F::zero())), + input_buffer: vec![], + output_buffer: vec![], + } + } + + /// Creates a new challenger with the same state as an existing challenger. + pub fn copy(&self, builder: &mut Builder) -> Self { + let DuplexChallengerVariable { sponge_state, input_buffer, output_buffer } = self; + let sponge_state = sponge_state.map(|x| builder.eval(x)); + let mut copy_vec = |v: &Vec>| v.iter().map(|x| builder.eval(*x)).collect(); + DuplexChallengerVariable:: { + sponge_state, + input_buffer: copy_vec(input_buffer), + output_buffer: copy_vec(output_buffer), + } + } + + // /// Asserts that the state of this challenger is equal to the state of another challenger. + // fn assert_eq(&self, builder: &mut Builder, other: &Self) { + // zip(&self.sponge_state, &other.sponge_state) + // .chain(zip(&self.input_buffer, &other.input_buffer)) + // .chain(zip(&self.output_buffer, &other.output_buffer)) + // .for_each(|(&element, &other_element)| { + // builder.assert_felt_eq(element, other_element); + // }); + // } + + // fn reset(&mut self, builder: &mut Builder) { + // self.sponge_state.fill(builder.eval(C::F::zero())); + // self.input_buffer.clear(); + // self.output_buffer.clear(); + // } + + fn observe(&mut self, builder: &mut Builder, value: Felt) { + self.output_buffer.clear(); + + self.input_buffer.push(value); + + if self.input_buffer.len() == HASH_RATE { + self.duplexing(builder); + } + } + + // fn observe_commitment(&mut self, builder: &mut Builder, commitment: DigestVariable) { + // for element in commitment { + // self.observe(builder, element); + // } + // } + + fn sample(&mut self, builder: &mut Builder) -> Felt { + if !self.input_buffer.is_empty() || self.output_buffer.is_empty() { + self.duplexing(builder); + } + + self.output_buffer.pop().expect("output buffer should be non-empty") + } + + fn sample_bits(&mut self, builder: &mut Builder, nb_bits: usize) -> Vec> { + assert!(nb_bits <= NUM_BITS); + let rand_f = self.sample(builder); + let mut rand_f_bits = builder.num2bits_v2_f(rand_f, NUM_BITS); + rand_f_bits.truncate(nb_bits); + rand_f_bits + } + + pub fn public_values(&self, builder: &mut Builder) -> ChallengerPublicValues> { + assert!(self.input_buffer.len() <= PERMUTATION_WIDTH); + assert!(self.output_buffer.len() <= PERMUTATION_WIDTH); + + let sponge_state = self.sponge_state; + let num_inputs = builder.eval(C::F::from_canonical_usize(self.input_buffer.len())); + let num_outputs = builder.eval(C::F::from_canonical_usize(self.output_buffer.len())); + + let input_buffer: [_; PERMUTATION_WIDTH] = self + .input_buffer + .iter() + .copied() + .chain((self.input_buffer.len()..PERMUTATION_WIDTH).map(|_| builder.eval(C::F::zero()))) + .collect::>() + .try_into() + .unwrap(); + + let output_buffer: [_; PERMUTATION_WIDTH] = self + .output_buffer + .iter() + .copied() + .chain( + (self.output_buffer.len()..PERMUTATION_WIDTH).map(|_| builder.eval(C::F::zero())), + ) + .collect::>() + .try_into() + .unwrap(); + + ChallengerPublicValues { + sponge_state, + num_inputs, + input_buffer, + num_outputs, + output_buffer, + } + } +} + +impl CanCopyChallenger for DuplexChallengerVariable { + fn copy(&self, builder: &mut Builder) -> Self { + DuplexChallengerVariable::copy(self, builder) + } +} + +impl CanObserveVariable> for DuplexChallengerVariable { + fn observe(&mut self, builder: &mut Builder, value: Felt) { + DuplexChallengerVariable::observe(self, builder, value); + } + + fn observe_slice( + &mut self, + builder: &mut Builder, + values: impl IntoIterator>, + ) { + for value in values { + self.observe(builder, value); + } + } +} + +impl CanObserveVariable; N]> + for DuplexChallengerVariable +{ + fn observe(&mut self, builder: &mut Builder, values: [Felt; N]) { + for value in values { + self.observe(builder, value); + } + } +} + +impl CanSampleVariable> for DuplexChallengerVariable { + fn sample(&mut self, builder: &mut Builder) -> Felt { + DuplexChallengerVariable::sample(self, builder) + } +} + +impl CanSampleBitsVariable> for DuplexChallengerVariable { + fn sample_bits(&mut self, builder: &mut Builder, nb_bits: usize) -> Vec> { + DuplexChallengerVariable::sample_bits(self, builder, nb_bits) + } +} + +impl FieldChallengerVariable> for DuplexChallengerVariable { + fn sample_ext(&mut self, builder: &mut Builder) -> Ext { + let a = self.sample(builder); + let b = self.sample(builder); + let c = self.sample(builder); + let d = self.sample(builder); + builder.ext_from_base_slice(&[a, b, c, d]) + } + + fn check_witness( + &mut self, + builder: &mut Builder, + nb_bits: usize, + witness: Felt<::F>, + ) { + self.observe(builder, witness); + let element_bits = self.sample_bits(builder, nb_bits); + for bit in element_bits { + builder.assert_felt_eq(bit, C::F::zero()); + } + } + + fn duplexing(&mut self, builder: &mut Builder) { + assert!(self.input_buffer.len() <= HASH_RATE); + + self.sponge_state[0..self.input_buffer.len()].copy_from_slice(self.input_buffer.as_slice()); + self.input_buffer.clear(); + + self.sponge_state = builder.poseidon2_permute_v2(self.sponge_state); + + self.output_buffer.clear(); + self.output_buffer.extend_from_slice(&self.sponge_state); + } +} + +#[derive(Clone)] +pub struct MultiField32ChallengerVariable { + sponge_state: [Var; 3], + input_buffer: Vec>, + output_buffer: Vec>, + num_f_elms: usize, +} + +impl MultiField32ChallengerVariable { + pub fn new(builder: &mut Builder) -> Self { + MultiField32ChallengerVariable:: { + sponge_state: [ + builder.eval(C::N::zero()), + builder.eval(C::N::zero()), + builder.eval(C::N::zero()), + ], + input_buffer: vec![], + output_buffer: vec![], + num_f_elms: C::N::bits() / 64, + } + } + + pub fn duplexing(&mut self, builder: &mut Builder) { + assert!(self.input_buffer.len() <= self.num_f_elms * SPONGE_SIZE); + + for (i, f_chunk) in self.input_buffer.chunks(self.num_f_elms).enumerate() { + self.sponge_state[i] = reduce_32(builder, f_chunk); + } + self.input_buffer.clear(); + + // TODO make this a method for the builder. + builder.push(DslIr::CircuitPoseidon2Permute(self.sponge_state)); + + self.output_buffer.clear(); + for &pf_val in self.sponge_state.iter() { + let f_vals = split_32(builder, pf_val, self.num_f_elms); + for f_val in f_vals { + self.output_buffer.push(f_val); + } + } + } + + pub fn observe(&mut self, builder: &mut Builder, value: Felt) { + self.output_buffer.clear(); + + self.input_buffer.push(value); + if self.input_buffer.len() == self.num_f_elms * SPONGE_SIZE { + self.duplexing(builder); + } + } + + pub fn observe_commitment( + &mut self, + builder: &mut Builder, + value: [Var; DIGEST_SIZE], + ) { + for val in value { + let f_vals: Vec> = split_32(builder, val, self.num_f_elms); + for f_val in f_vals { + self.observe(builder, f_val); + } + } + } + + pub fn sample(&mut self, builder: &mut Builder) -> Felt { + if !self.input_buffer.is_empty() || self.output_buffer.is_empty() { + self.duplexing(builder); + } + + self.output_buffer.pop().expect("output buffer should be non-empty") + } + + pub fn sample_ext(&mut self, builder: &mut Builder) -> Ext { + let a = self.sample(builder); + let b = self.sample(builder); + let c = self.sample(builder); + let d = self.sample(builder); + builder.felts2ext(&[a, b, c, d]) + } + + pub fn sample_bits(&mut self, builder: &mut Builder, bits: usize) -> Vec> { + let rand_f = self.sample(builder); + builder.num2bits_f_circuit(rand_f)[0..bits].to_vec() + } + + pub fn check_witness(&mut self, builder: &mut Builder, bits: usize, witness: Felt) { + self.observe(builder, witness); + let element = self.sample_bits(builder, bits); + for bit in element { + builder.assert_var_eq(bit, C::N::from_canonical_usize(0)); + } + } +} + +impl CanCopyChallenger for MultiField32ChallengerVariable { + /// Creates a new challenger with the same state as an existing challenger. + fn copy(&self, builder: &mut Builder) -> Self { + let MultiField32ChallengerVariable { + sponge_state, + input_buffer, + output_buffer, + num_f_elms, + } = self; + let sponge_state = sponge_state.map(|x| builder.eval(x)); + let mut copy_vec = |v: &Vec>| v.iter().map(|x| builder.eval(*x)).collect(); + MultiField32ChallengerVariable:: { + sponge_state, + num_f_elms: *num_f_elms, + input_buffer: copy_vec(input_buffer), + output_buffer: copy_vec(output_buffer), + } + } +} + +impl CanObserveVariable> for MultiField32ChallengerVariable { + fn observe(&mut self, builder: &mut Builder, value: Felt) { + MultiField32ChallengerVariable::observe(self, builder, value); + } +} + +impl CanObserveVariable; DIGEST_SIZE]> + for MultiField32ChallengerVariable +{ + fn observe(&mut self, builder: &mut Builder, value: [Var; DIGEST_SIZE]) { + self.observe_commitment(builder, value) + } +} + +impl CanObserveVariable> for MultiField32ChallengerVariable { + fn observe(&mut self, builder: &mut Builder, value: Var) { + self.observe_commitment(builder, [value]) + } +} + +impl CanSampleVariable> for MultiField32ChallengerVariable { + fn sample(&mut self, builder: &mut Builder) -> Felt { + MultiField32ChallengerVariable::sample(self, builder) + } +} + +impl CanSampleBitsVariable> for MultiField32ChallengerVariable { + fn sample_bits(&mut self, builder: &mut Builder, bits: usize) -> Vec> { + MultiField32ChallengerVariable::sample_bits(self, builder, bits) + } +} + +impl FieldChallengerVariable> for MultiField32ChallengerVariable { + fn sample_ext(&mut self, builder: &mut Builder) -> Ext { + MultiField32ChallengerVariable::sample_ext(self, builder) + } + + fn check_witness(&mut self, builder: &mut Builder, bits: usize, witness: Felt) { + MultiField32ChallengerVariable::check_witness(self, builder, bits, witness); + } + + fn duplexing(&mut self, builder: &mut Builder) { + MultiField32ChallengerVariable::duplexing(self, builder); + } +} + +pub fn reduce_32(builder: &mut Builder, vals: &[Felt]) -> Var { + let mut power = C::N::one(); + let result: Var = builder.eval(C::N::zero()); + for val in vals.iter() { + let val = builder.felt2var_circuit(*val); + builder.assign(result, result + val * power); + power *= C::N::from_canonical_u64(1u64 << 32); + } + result +} + +pub fn split_32(builder: &mut Builder, val: Var, n: usize) -> Vec> { + let bits = builder.num2bits_v_circuit(val, 256); + let mut results = Vec::new(); + for i in 0..n { + let result: Felt = builder.eval(C::F::zero()); + for j in 0..64 { + let bit = bits[i * 64 + j]; + let t = builder.eval(result + C::F::from_wrapped_u64(1 << j)); + let z = builder.select_f(bit, t, result); + builder.assign(result, z); + } + results.push(result); + } + results +} + +#[cfg(test)] +pub(crate) mod tests { + use std::iter::zip; + + use crate::{ + challenger::{CanCopyChallenger, MultiField32ChallengerVariable}, + hash::{FieldHasherVariable, BN254_DIGEST_SIZE}, + utils::tests::run_test_recursion, + }; + use p3_baby_bear::BabyBear; + use p3_bn254_fr::Bn254Fr; + use p3_challenger::{CanObserve, CanSample, CanSampleBits, FieldChallenger}; + use p3_field::AbstractField; + use p3_symmetric::{CryptographicHasher, Hash, PseudoCompressionFunction}; + use sp1_recursion_compiler::{ + asm::{AsmBuilder, AsmConfig}, + config::OuterConfig, + constraints::ConstraintCompiler, + ir::{Builder, Config, Ext, ExtConst, Felt, Var}, + }; + use sp1_recursion_core_v2::stark::config::{ + outer_perm, BabyBearPoseidon2Outer, OuterCompress, OuterHash, + }; + use sp1_recursion_gnark_ffi::PlonkBn254Prover; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; + + use crate::{ + challenger::{DuplexChallengerVariable, FieldChallengerVariable}, + witness::OuterWitness, + }; + + type SC = BabyBearPoseidon2; + type C = OuterConfig; + type F = ::Val; + type EF = ::Challenge; + + #[test] + fn test_compiler_challenger() { + let config = SC::default(); + let mut challenger = config.challenger(); + challenger.observe(F::one()); + challenger.observe(F::two()); + challenger.observe(F::two()); + challenger.observe(F::two()); + let result: F = challenger.sample(); + println!("expected result: {}", result); + let result_ef: EF = challenger.sample_ext_element(); + println!("expected result_ef: {}", result_ef); + + let mut builder = AsmBuilder::::default(); + + let mut challenger = DuplexChallengerVariable::> { + sponge_state: core::array::from_fn(|_| builder.eval(F::zero())), + input_buffer: vec![], + output_buffer: vec![], + }; + let one: Felt<_> = builder.eval(F::one()); + let two: Felt<_> = builder.eval(F::two()); + + challenger.observe(&mut builder, one); + challenger.observe(&mut builder, two); + challenger.observe(&mut builder, two); + challenger.observe(&mut builder, two); + let element = challenger.sample(&mut builder); + let element_ef = challenger.sample_ext(&mut builder); + + let expected_result: Felt<_> = builder.eval(result); + let expected_result_ef: Ext<_, _> = builder.eval(result_ef.cons()); + builder.print_f(element); + builder.assert_felt_eq(expected_result, element); + builder.print_e(element_ef); + builder.assert_ext_eq(expected_result_ef, element_ef); + + run_test_recursion(builder.operations, None); + } + + #[test] + fn test_challenger_outer() { + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + type EF = ::Challenge; + type N = ::N; + + let config = SC::default(); + let mut challenger = config.challenger(); + challenger.observe(F::one()); + challenger.observe(F::two()); + challenger.observe(F::two()); + challenger.observe(F::two()); + let commit = Hash::from([N::two()]); + challenger.observe(commit); + let result: F = challenger.sample(); + println!("expected result: {}", result); + let result_ef: EF = challenger.sample_ext_element(); + println!("expected result_ef: {}", result_ef); + let mut bits = challenger.sample_bits(30); + let mut bits_vec = vec![]; + for _ in 0..30 { + bits_vec.push(bits % 2); + bits >>= 1; + } + println!("expected bits: {:?}", bits_vec); + + let mut builder = Builder::::default(); + + // let width: Var<_> = builder.eval(F::from_canonical_usize(PERMUTATION_WIDTH)); + let mut challenger = MultiField32ChallengerVariable::::new(&mut builder); + let one: Felt<_> = builder.eval(F::one()); + let two: Felt<_> = builder.eval(F::two()); + let two_var: Var<_> = builder.eval(N::two()); + // builder.halt(); + challenger.observe(&mut builder, one); + challenger.observe(&mut builder, two); + challenger.observe(&mut builder, two); + challenger.observe(&mut builder, two); + challenger.observe_commitment(&mut builder, [two_var]); + + // Check to make sure the copying works. + challenger = challenger.copy(&mut builder); + let element = challenger.sample(&mut builder); + let element_ef = challenger.sample_ext(&mut builder); + let bits = challenger.sample_bits(&mut builder, 31); + + let expected_result: Felt<_> = builder.eval(result); + let expected_result_ef: Ext<_, _> = builder.eval(result_ef.cons()); + builder.print_f(element); + builder.assert_felt_eq(expected_result, element); + builder.print_e(element_ef); + builder.assert_ext_eq(expected_result_ef, element_ef); + for (expected_bit, bit) in zip(bits_vec.iter(), bits.iter()) { + let expected_bit: Var<_> = builder.eval(N::from_canonical_usize(*expected_bit)); + builder.print_v(*bit); + builder.assert_var_eq(expected_bit, *bit); + } + + let mut backend = ConstraintCompiler::::default(); + let constraints = backend.emit(builder.operations); + let witness = OuterWitness::default(); + PlonkBn254Prover::test::(constraints, witness); + } + + #[test] + fn test_select_chain_digest() { + type N = ::N; + + let mut builder = Builder::::default(); + + let one: Var<_> = builder.eval(N::one()); + let two: Var<_> = builder.eval(N::two()); + + let to_swap = [[one], [two]]; + let result = BabyBearPoseidon2Outer::select_chain_digest(&mut builder, one, to_swap); + + builder.assert_var_eq(result[0][0], two); + builder.assert_var_eq(result[1][0], one); + + let mut backend = ConstraintCompiler::::default(); + let constraints = backend.emit(builder.operations); + let witness = OuterWitness::default(); + PlonkBn254Prover::test::(constraints, witness); + } + + #[test] + fn test_p2_hash() { + let perm = outer_perm(); + let hasher = OuterHash::new(perm.clone()).unwrap(); + + let input: [BabyBear; 7] = [ + BabyBear::from_canonical_u32(0), + BabyBear::from_canonical_u32(1), + BabyBear::from_canonical_u32(2), + BabyBear::from_canonical_u32(2), + BabyBear::from_canonical_u32(2), + BabyBear::from_canonical_u32(2), + BabyBear::from_canonical_u32(2), + ]; + let output = hasher.hash_iter(input); + + let mut builder = Builder::::default(); + let a: Felt<_> = builder.eval(input[0]); + let b: Felt<_> = builder.eval(input[1]); + let c: Felt<_> = builder.eval(input[2]); + let d: Felt<_> = builder.eval(input[3]); + let e: Felt<_> = builder.eval(input[4]); + let f: Felt<_> = builder.eval(input[5]); + let g: Felt<_> = builder.eval(input[6]); + let result = BabyBearPoseidon2Outer::hash(&mut builder, &[a, b, c, d, e, f, g]); + + builder.assert_var_eq(result[0], output[0]); + + let mut backend = ConstraintCompiler::::default(); + let constraints = backend.emit(builder.operations); + PlonkBn254Prover::test::(constraints.clone(), OuterWitness::default()); + } + + #[test] + fn test_p2_compress() { + type OuterDigestVariable = [Var<::N>; BN254_DIGEST_SIZE]; + let perm = outer_perm(); + let compressor = OuterCompress::new(perm.clone()); + + let a: [Bn254Fr; 1] = [Bn254Fr::two()]; + let b: [Bn254Fr; 1] = [Bn254Fr::two()]; + let gt = compressor.compress([a, b]); + + let mut builder = Builder::::default(); + let a: OuterDigestVariable = [builder.eval(a[0])]; + let b: OuterDigestVariable = [builder.eval(b[0])]; + let result = BabyBearPoseidon2Outer::compress(&mut builder, [a, b]); + builder.assert_var_eq(result[0], gt[0]); + + let mut backend = ConstraintCompiler::::default(); + let constraints = backend.emit(builder.operations); + PlonkBn254Prover::test::(constraints.clone(), OuterWitness::default()); + } +} diff --git a/crates/recursion/circuit-v2/src/constraints.rs b/crates/recursion/circuit-v2/src/constraints.rs new file mode 100644 index 0000000000..1512d144ae --- /dev/null +++ b/crates/recursion/circuit-v2/src/constraints.rs @@ -0,0 +1,237 @@ +use p3_air::{Air, BaseAir}; +use p3_baby_bear::BabyBear; +use p3_commit::{LagrangeSelectors, Mmcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; +use p3_field::{AbstractExtensionField, AbstractField, TwoAdicField}; +use p3_matrix::dense::RowMajorMatrix; + +use sp1_recursion_compiler::ir::{ + Builder, Config, Ext, ExtensionOperand, Felt, SymbolicExt, SymbolicFelt, +}; +use sp1_stark::{ + air::MachineAir, AirOpenedValues, ChipOpenedValues, GenericVerifierConstraintFolder, + MachineChip, OpeningShapeError, +}; + +use crate::{ + domain::PolynomialSpaceVariable, stark::StarkVerifier, BabyBearFriConfigVariable, CircuitConfig, +}; + +pub type RecursiveVerifierConstraintFolder<'a, C> = GenericVerifierConstraintFolder< + 'a, + ::F, + ::EF, + Felt<::F>, + Ext<::F, ::EF>, + SymbolicExt<::F, ::EF>, +>; + +impl StarkVerifier +where + C::F: TwoAdicField, + SC: BabyBearFriConfigVariable, + C: CircuitConfig, + >::ProverData>: Clone, + A: MachineAir + for<'a> Air>, +{ + #[allow(clippy::too_many_arguments)] + pub fn verify_constraints( + builder: &mut Builder, + chip: &MachineChip, + opening: &ChipOpenedValues>, + trace_domain: TwoAdicMultiplicativeCoset, + qc_domains: Vec>, + zeta: Ext, + alpha: Ext, + permutation_challenges: &[Ext], + public_values: &[Felt], + ) { + let sels = trace_domain.selectors_at_point_variable(builder, zeta); + + // Recompute the quotient at zeta from the chunks. + let quotient = Self::recompute_quotient(builder, opening, &qc_domains, zeta); + + // Calculate the evaluations of the constraints at zeta. + let folded_constraints = Self::eval_constraints( + builder, + chip, + opening, + &sels, + alpha, + permutation_challenges, + public_values, + ); + + // Assert that the quotient times the zerofier is equal to the folded constraints. + builder.assert_ext_eq(folded_constraints * sels.inv_zeroifier, quotient); + } + + pub fn eval_constraints( + builder: &mut Builder, + chip: &MachineChip, + opening: &ChipOpenedValues>, + selectors: &LagrangeSelectors>, + alpha: Ext, + permutation_challenges: &[Ext], + public_values: &[Felt], + ) -> Ext { + let mut unflatten = |v: &[Ext]| { + v.chunks_exact(>::D) + .map(|chunk| { + builder.eval( + chunk + .iter() + .enumerate() + .map( + |(e_i, x): (usize, &Ext)| -> SymbolicExt { + SymbolicExt::from(*x) * C::EF::monomial(e_i) + }, + ) + .sum::>(), + ) + }) + .collect::>>() + }; + let perm_opening = AirOpenedValues { + local: unflatten(&opening.permutation.local), + next: unflatten(&opening.permutation.next), + }; + + let mut folder = RecursiveVerifierConstraintFolder:: { + preprocessed: opening.preprocessed.view(), + main: opening.main.view(), + perm: perm_opening.view(), + perm_challenges: permutation_challenges, + cumulative_sum: opening.cumulative_sum, + public_values, + is_first_row: selectors.is_first_row, + is_last_row: selectors.is_last_row, + is_transition: selectors.is_transition, + alpha, + accumulator: SymbolicExt::zero(), + _marker: std::marker::PhantomData, + }; + + chip.eval(&mut folder); + builder.eval(folder.accumulator) + } + + pub fn recompute_quotient( + builder: &mut Builder, + opening: &ChipOpenedValues>, + qc_domains: &[TwoAdicMultiplicativeCoset], + zeta: Ext, + ) -> Ext { + let zps = qc_domains + .iter() + .enumerate() + .map(|(i, domain)| { + let (zs, zinvs) = qc_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + let first_point = builder.eval(domain.first_point()); + ( + other_domain + .zp_at_point_variable(builder, zeta) + .to_operand() + .symbolic(), + other_domain.zp_at_point_f(builder, first_point).inverse(), + ) + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + zs.into_iter().product::>() + * zinvs.into_iter().product::>() + }) + .collect::>>() + .into_iter() + .map(|x| builder.eval(x)) + .collect::>>(); + + builder.eval( + opening + .quotient + .iter() + .enumerate() + .map(|(ch_i, ch)| { + assert_eq!(ch.len(), C::EF::D); + ch.iter() + .enumerate() + .map(|(e_i, &c)| zps[ch_i] * C::EF::monomial(e_i) * c) + .sum::>() + }) + .sum::>(), + ) + } + + pub fn verify_opening_shape( + chip: &MachineChip, + opening: &ChipOpenedValues>, + ) -> Result<(), OpeningShapeError> { + // Verify that the preprocessed width matches the expected value for the chip. + if opening.preprocessed.local.len() != chip.preprocessed_width() { + return Err(OpeningShapeError::PreprocessedWidthMismatch( + chip.preprocessed_width(), + opening.preprocessed.local.len(), + )); + } + if opening.preprocessed.next.len() != chip.preprocessed_width() { + return Err(OpeningShapeError::PreprocessedWidthMismatch( + chip.preprocessed_width(), + opening.preprocessed.next.len(), + )); + } + + // Verify that the main width matches the expected value for the chip. + if opening.main.local.len() != chip.width() { + return Err(OpeningShapeError::MainWidthMismatch( + chip.width(), + opening.main.local.len(), + )); + } + if opening.main.next.len() != chip.width() { + return Err(OpeningShapeError::MainWidthMismatch( + chip.width(), + opening.main.next.len(), + )); + } + + // Verify that the permutation width matches the expected value for the chip. + if opening.permutation.local.len() + != chip.permutation_width() * >::D + { + return Err(OpeningShapeError::PermutationWidthMismatch( + chip.permutation_width(), + opening.permutation.local.len(), + )); + } + if opening.permutation.next.len() + != chip.permutation_width() * >::D + { + return Err(OpeningShapeError::PermutationWidthMismatch( + chip.permutation_width(), + opening.permutation.next.len(), + )); + } + + // Verift that the number of quotient chunks matches the expected value for the chip. + if opening.quotient.len() != chip.quotient_width() { + return Err(OpeningShapeError::QuotientWidthMismatch( + chip.quotient_width(), + opening.quotient.len(), + )); + } + // For each quotient chunk, verify that the number of elements is equal to the degree of the + // challenge extension field over the value field. + for slice in &opening.quotient { + if slice.len() != >::D { + return Err(OpeningShapeError::QuotientChunkSizeMismatch( + >::D, + slice.len(), + )); + } + } + + Ok(()) + } +} diff --git a/crates/recursion/circuit-v2/src/domain.rs b/crates/recursion/circuit-v2/src/domain.rs new file mode 100644 index 0000000000..7c16673615 --- /dev/null +++ b/crates/recursion/circuit-v2/src/domain.rs @@ -0,0 +1,89 @@ +use p3_commit::{LagrangeSelectors, PolynomialSpace, TwoAdicMultiplicativeCoset}; +use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; +use sp1_recursion_compiler::prelude::*; + +/// Reference: [p3_commit::PolynomialSpace] +pub trait PolynomialSpaceVariable: Sized + PolynomialSpace { + fn selectors_at_point_variable( + &self, + builder: &mut Builder, + point: Ext, + ) -> LagrangeSelectors>; + + fn zp_at_point_variable( + &self, + builder: &mut Builder, + point: Ext, + ) -> Ext; + + fn next_point_variable( + &self, + builder: &mut Builder, + point: Ext<::F, ::EF>, + ) -> Ext<::F, ::EF>; + + fn zp_at_point_f( + &self, + builder: &mut Builder, + point: Felt<::F>, + ) -> Felt<::F>; +} + +impl PolynomialSpaceVariable for TwoAdicMultiplicativeCoset +where + C::F: TwoAdicField, +{ + fn next_point_variable( + &self, + builder: &mut Builder, + point: Ext<::F, ::EF>, + ) -> Ext<::F, ::EF> { + let g = C::F::two_adic_generator(self.log_n); + // let g: Felt<_> = builder.eval(g); + builder.eval(point * g) + } + + fn selectors_at_point_variable( + &self, + builder: &mut Builder, + point: Ext<::F, ::EF>, + ) -> LagrangeSelectors::F, ::EF>> { + let unshifted_point: Ext<_, _> = builder.eval(point * self.shift.inverse()); + let z_h_expr = builder + .exp_power_of_2_v::>(unshifted_point, Usize::Const(self.log_n)) + - C::EF::one(); + let z_h: Ext<_, _> = builder.eval(z_h_expr); + let g = C::F::two_adic_generator(self.log_n); + let ginv = g.inverse(); + LagrangeSelectors { + is_first_row: builder.eval(z_h / (unshifted_point - C::EF::one())), + is_last_row: builder.eval(z_h / (unshifted_point - ginv)), + is_transition: builder.eval(unshifted_point - ginv), + inv_zeroifier: builder.eval(z_h.inverse()), + } + } + + fn zp_at_point_variable( + &self, + builder: &mut Builder, + point: Ext<::F, ::EF>, + ) -> Ext<::F, ::EF> { + let unshifted_power = builder.exp_power_of_2_v::>( + point + * C::EF::from_base_slice(&[self.shift, C::F::zero(), C::F::zero(), C::F::zero()]) + .inverse() + .cons(), + Usize::Const(self.log_n), + ); + builder.eval(unshifted_power - C::EF::one()) + } + fn zp_at_point_f( + &self, + builder: &mut Builder, + point: Felt<::F>, + ) -> Felt<::F> { + let unshifted_power = builder + .exp_power_of_2_v::>(point * self.shift.inverse(), Usize::Const(self.log_n)); + builder.eval(unshifted_power - C::F::one()) + } +} diff --git a/crates/recursion/circuit-v2/src/fri.rs b/crates/recursion/circuit-v2/src/fri.rs new file mode 100644 index 0000000000..9ad2b73693 --- /dev/null +++ b/crates/recursion/circuit-v2/src/fri.rs @@ -0,0 +1,637 @@ +use itertools::{izip, Itertools}; +use p3_baby_bear::BabyBear; +use p3_commit::PolynomialSpace; +use p3_field::{AbstractField, TwoAdicField}; +use p3_fri::FriConfig; +use p3_matrix::Dimensions; +use p3_util::log2_strict_usize; +use sp1_recursion_compiler::ir::{Builder, Felt, SymbolicExt, SymbolicFelt}; +use std::{ + cmp::Reverse, + iter::{once, repeat_with, zip}, +}; + +use crate::{ + challenger::{CanSampleBitsVariable, FieldChallengerVariable}, + BabyBearFriConfigVariable, CanObserveVariable, CircuitConfig, Ext, FriChallenges, FriMmcs, + FriProofVariable, FriQueryProofVariable, TwoAdicPcsProofVariable, TwoAdicPcsRoundVariable, +}; + +pub fn verify_shape_and_sample_challenges< + C: CircuitConfig, + SC: BabyBearFriConfigVariable, +>( + builder: &mut Builder, + config: &FriConfig>, + proof: &FriProofVariable, + challenger: &mut SC::FriChallengerVariable, +) -> FriChallenges { + let betas = proof + .commit_phase_commits + .iter() + .map(|commitment| { + challenger.observe(builder, *commitment); + challenger.sample_ext(builder) + }) + .collect(); + + // Observe the final polynomial. + let final_poly_felts = C::ext2felt(builder, proof.final_poly); + final_poly_felts.iter().for_each(|felt| { + challenger.observe(builder, *felt); + }); + + assert_eq!(proof.query_proofs.len(), config.num_queries); + challenger.check_witness(builder, config.proof_of_work_bits, proof.pow_witness); + + let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; + let query_indices: Vec> = + repeat_with(|| challenger.sample_bits(builder, log_max_height)) + .take(config.num_queries) + .collect(); + + FriChallenges { query_indices, betas } +} + +pub fn verify_two_adic_pcs, SC: BabyBearFriConfigVariable>( + builder: &mut Builder, + config: &FriConfig>, + proof: &TwoAdicPcsProofVariable, + challenger: &mut SC::FriChallengerVariable, + rounds: Vec>, +) { + let alpha = challenger.sample_ext(builder); + + let fri_challenges = + verify_shape_and_sample_challenges::(builder, config, &proof.fri_proof, challenger); + + let log_global_max_height = proof.fri_proof.commit_phase_commits.len() + config.log_blowup; + + // The powers of alpha, where the ith element is alpha^i. + let mut alpha_pows: Vec> = + vec![builder.eval(SymbolicExt::from_f(C::EF::one()))]; + + let reduced_openings = proof + .query_openings + .iter() + .zip(&fri_challenges.query_indices) + .map(|(query_opening, index_bits)| { + // The powers of alpha, where the ith element is alpha^i. + let mut log_height_pow = [0usize; 32]; + let mut ro: [Ext; 32] = + [builder.eval(SymbolicExt::from_f(C::EF::zero())); 32]; + + for (batch_opening, round) in zip(query_opening, rounds.iter().cloned()) { + let batch_commit = round.batch_commit; + let mats = round.domains_points_and_opens; + let batch_heights = + mats.iter().map(|mat| mat.domain.size() << config.log_blowup).collect_vec(); + let batch_dims = batch_heights + .iter() + .map(|&height| Dimensions { width: 0, height }) + .collect_vec(); + + let batch_max_height = batch_heights.iter().max().expect("Empty batch?"); + let log_batch_max_height = log2_strict_usize(*batch_max_height); + let bits_reduced = log_global_max_height - log_batch_max_height; + + let reduced_index_bits = index_bits[bits_reduced..].to_vec(); + + verify_batch::( + builder, + batch_commit, + batch_dims, + reduced_index_bits, + batch_opening.opened_values.clone(), + batch_opening.opening_proof.clone(), + ); + + for (mat_opening, mat) in izip!(&batch_opening.opened_values, mats) { + let mat_domain = mat.domain; + let mat_points = mat.points; + let mat_values = mat.values; + let log_height = log2_strict_usize(mat_domain.size()) + config.log_blowup; + + let bits_reduced = log_global_max_height - log_height; + let reduced_index_bits_trunc = + index_bits[bits_reduced..(bits_reduced + log_height)].to_vec(); + + let g = builder.generator(); + let two_adic_generator: Felt<_> = + builder.eval(C::F::two_adic_generator(log_height)); + let two_adic_generator_exp = + C::exp_reverse_bits(builder, two_adic_generator, reduced_index_bits_trunc); + let x: Felt<_> = builder.eval(g * two_adic_generator_exp); + + for (z, ps_at_z) in izip!(mat_points, mat_values) { + // builder.cycle_tracker("2adic-hotloop"); + let mut acc: Ext = + builder.eval(SymbolicExt::from_f(C::EF::zero())); + for (p_at_x, p_at_z) in izip!(mat_opening.clone(), ps_at_z) { + let pow = log_height_pow[log_height]; + // Fill in any missing powers of alpha. + (alpha_pows.len()..pow + 1).for_each(|_| { + let new_alpha = builder.eval(*alpha_pows.last().unwrap() * alpha); + builder.reduce_e(new_alpha); + alpha_pows.push(new_alpha); + }); + acc = builder.eval(acc + (alpha_pows[pow] * (p_at_z - p_at_x[0]))); + log_height_pow[log_height] += 1; + } + ro[log_height] = builder.eval(ro[log_height] + acc / (z - x)); + // builder.cycle_tracker("2adic-hotloop"); + } + } + } + ro + }) + .collect::>(); + + verify_challenges::( + builder, + config, + &proof.fri_proof, + &fri_challenges, + reduced_openings, + ); +} + +pub fn verify_challenges, SC: BabyBearFriConfigVariable>( + builder: &mut Builder, + config: &FriConfig>, + proof: &FriProofVariable, + challenges: &FriChallenges, + reduced_openings: Vec<[Ext; 32]>, +) { + let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; + for ((index_bits, query_proof), ro) in + challenges.query_indices.iter().zip(&proof.query_proofs).zip(reduced_openings) + { + let folded_eval = verify_query::( + builder, + proof.commit_phase_commits.clone(), + index_bits, + query_proof.clone(), + challenges.betas.clone(), + ro, + log_max_height, + ); + + builder.assert_ext_eq(folded_eval, proof.final_poly); + } +} + +pub fn verify_query, SC: BabyBearFriConfigVariable>( + builder: &mut Builder, + commit_phase_commits: Vec, + index_bits: &[C::Bit], + proof: FriQueryProofVariable, + betas: Vec>, + reduced_openings: [Ext; 32], + log_max_height: usize, +) -> Ext { + let mut folded_eval: Ext<_, _> = builder.constant(C::EF::zero()); + let two_adic_generator: Felt<_> = builder.constant(C::F::two_adic_generator(log_max_height)); + + let x_felt = + C::exp_reverse_bits(builder, two_adic_generator, index_bits[..log_max_height].to_vec()); + let mut x: Ext<_, _> = builder.eval(SymbolicExt::one() * SymbolicFelt::from(x_felt)); + + for (offset, log_folded_height, commit, step, beta) in izip!( + 0.., + (0..log_max_height).rev(), + commit_phase_commits, + &proof.commit_phase_openings, + betas, + ) { + folded_eval = builder.eval(folded_eval + reduced_openings[log_folded_height + 1]); + + let index_sibling_complement: C::Bit = index_bits[offset].clone(); + // let index_sibling_complement: Felt<_> = builder.constant(C::F::one()); + let index_pair = &index_bits[(offset + 1)..]; + + builder.reduce_e(folded_eval); + + let evals_ext = C::select_chain_ef( + builder, + index_sibling_complement.clone(), + once(folded_eval), + once(step.sibling_value), + ); + let evals_felt = vec![ + C::ext2felt(builder, evals_ext[0]).to_vec(), + C::ext2felt(builder, evals_ext[1]).to_vec(), + ]; + + let dims = &[Dimensions { width: 2, height: (1 << log_folded_height) }]; + verify_batch::( + builder, + commit, + dims.to_vec(), + index_pair.to_vec(), + [evals_felt].to_vec(), + step.opening_proof.clone(), + ); + + let xs_new: Ext<_, _> = builder.eval(x * C::EF::two_adic_generator(1)); + let xs = C::select_chain_ef(builder, index_sibling_complement, once(x), once(xs_new)); + folded_eval = builder + .eval(evals_ext[0] + (beta - xs[0]) * (evals_ext[1] - evals_ext[0]) / (xs[1] - xs[0])); + x = builder.eval(x * x); + } + + folded_eval +} + +pub fn verify_batch, SC: BabyBearFriConfigVariable>( + builder: &mut Builder, + commit: SC::Digest, + dimensions: Vec, + index_bits: Vec, + opened_values: Vec>>>, + proof: Vec, +) { + let mut heights_tallest_first = + dimensions.iter().enumerate().sorted_by_key(|(_, dims)| Reverse(dims.height)).peekable(); + + let mut curr_height_padded = heights_tallest_first.peek().unwrap().1.height.next_power_of_two(); + + let ext_slice: Vec>> = heights_tallest_first + .peeking_take_while(|(_, dims)| dims.height.next_power_of_two() == curr_height_padded) + .flat_map(|(i, _)| opened_values[i].as_slice()) + .cloned() + .collect::>(); + let felt_slice: Vec> = + ext_slice.iter().flat_map(|ext| ext.as_slice()).cloned().collect::>(); + let mut root: SC::Digest = SC::hash(builder, &felt_slice[..]); + + zip(index_bits, proof).for_each(|(bit, sibling): (C::Bit, SC::Digest)| { + let compress_args = SC::select_chain_digest(builder, bit, [root, sibling]); + + root = SC::compress(builder, compress_args); + curr_height_padded >>= 1; + + let next_height = heights_tallest_first + .peek() + .map(|(_, dims)| dims.height) + .filter(|h| h.next_power_of_two() == curr_height_padded); + + if let Some(next_height) = next_height { + let ext_slice: Vec>> = heights_tallest_first + .peeking_take_while(|(_, dims)| dims.height == next_height) + .flat_map(|(i, _)| opened_values[i].as_slice()) + .cloned() + .collect::>(); + let felt_slice: Vec> = + ext_slice.iter().flat_map(|ext| ext.as_slice()).cloned().collect::>(); + let next_height_openings_digest = SC::hash(builder, &felt_slice); + root = SC::compress(builder, [root, next_height_openings_digest]); + } + }); + + SC::assert_digest_eq(builder, root, commit); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + challenger::DuplexChallengerVariable, utils::tests::run_test_recursion, + BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, + FriQueryProofVariable, TwoAdicPcsMatsVariable, TwoAdicPcsProofVariable, + }; + use p3_challenger::{CanObserve, CanSample, FieldChallenger}; + use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; + use p3_field::AbstractField; + use p3_fri::{verifier, TwoAdicFriPcsProof}; + use p3_matrix::dense::RowMajorMatrix; + use rand::{ + rngs::{OsRng, StdRng}, + SeedableRng, + }; + use sp1_recursion_compiler::{ + asm::AsmBuilder, + config::InnerConfig, + ir::{Builder, Ext, SymbolicExt}, + }; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, inner_fri_config, inner_perm, InnerChallenge, + InnerChallengeMmcs, InnerChallenger, InnerCompress, InnerDft, InnerFriProof, InnerHash, + InnerPcs, InnerVal, InnerValMmcs, StarkGenericConfig, + }; + + use sp1_recursion_core_v2::DIGEST_SIZE; + + use crate::Digest; + + type C = InnerConfig; + type SC = BabyBearPoseidon2; + type F = ::Val; + type EF = ::Challenge; + + pub fn const_fri_proof( + builder: &mut AsmBuilder, + fri_proof: InnerFriProof, + ) -> FriProofVariable { + // Set the commit phase commits. + let commit_phase_commits = fri_proof + .commit_phase_commits + .iter() + .map(|commit| { + let commit: [F; DIGEST_SIZE] = (*commit).into(); + commit.map(|x| builder.eval(x)) + }) + .collect::>(); + + // Set the query proofs. + let query_proofs = fri_proof + .query_proofs + .iter() + .map(|query_proof| { + let commit_phase_openings = query_proof + .commit_phase_openings + .iter() + .map(|commit_phase_opening| { + let sibling_value = + builder.eval(SymbolicExt::from_f(commit_phase_opening.sibling_value)); + let opening_proof = commit_phase_opening + .opening_proof + .iter() + .map(|sibling| sibling.map(|x| builder.eval(x))) + .collect::>(); + FriCommitPhaseProofStepVariable { sibling_value, opening_proof } + }) + .collect::>(); + FriQueryProofVariable { commit_phase_openings } + }) + .collect::>(); + + // Initialize the FRI proof variable. + FriProofVariable { + commit_phase_commits, + query_proofs, + final_poly: builder.eval(SymbolicExt::from_f(fri_proof.final_poly)), + pow_witness: builder.eval(fri_proof.pow_witness), + } + } + + pub fn const_two_adic_pcs_proof( + builder: &mut Builder, + proof: TwoAdicFriPcsProof, + ) -> TwoAdicPcsProofVariable { + let fri_proof = const_fri_proof(builder, proof.fri_proof); + let query_openings = proof + .query_openings + .iter() + .map(|query_opening| { + query_opening + .iter() + .map(|opening| BatchOpeningVariable { + opened_values: opening + .opened_values + .iter() + .map(|opened_value| { + opened_value + .iter() + .map(|value| vec![builder.eval::, _>(*value)]) + .collect::>() + }) + .collect::>(), + opening_proof: opening + .opening_proof + .iter() + .map(|opening_proof| opening_proof.map(|x| builder.eval(x))) + .collect::>(), + }) + .collect::>() + }) + .collect::>(); + TwoAdicPcsProofVariable { fri_proof, query_openings } + } + + #[allow(clippy::type_complexity)] + pub fn const_two_adic_pcs_rounds( + builder: &mut Builder, + commit: [F; DIGEST_SIZE], + os: Vec<(TwoAdicMultiplicativeCoset, Vec<(InnerChallenge, Vec)>)>, + ) -> (Digest, Vec>) { + let commit: Digest = commit.map(|x| builder.eval(x)); + + let mut domains_points_and_opens = Vec::new(); + for (domain, poly) in os.into_iter() { + let points: Vec> = + poly.iter().map(|(p, _)| builder.eval(SymbolicExt::from_f(*p))).collect::>(); + let values: Vec>> = poly + .iter() + .map(|(_, v)| { + v.clone() + .iter() + .map(|t| builder.eval(SymbolicExt::from_f(*t))) + .collect::>() + }) + .collect::>(); + let domain_points_and_values = TwoAdicPcsMatsVariable { domain, points, values }; + domains_points_and_opens.push(domain_points_and_values); + } + + (commit, vec![TwoAdicPcsRoundVariable { batch_commit: commit, domains_points_and_opens }]) + } + + /// Reference: https://github.com/Plonky3/Plonky3/blob/4809fa7bedd9ba8f6f5d3267b1592618e3776c57/merkle-tree/src/mmcs.rs#L421 + #[test] + fn size_gaps() { + use p3_commit::Mmcs; + let perm = inner_perm(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm); + let mmcs = InnerValMmcs::new(hash, compress); + + let mut builder = Builder::::default(); + + // 4 mats with 1000 rows, 8 columns + let large_mats = (0..4).map(|_| RowMajorMatrix::::rand(&mut OsRng, 1000, 8)); + let large_mat_dims = (0..4).map(|_| Dimensions { height: 1000, width: 8 }); + + // 5 mats with 70 rows, 8 columns + let medium_mats = (0..5).map(|_| RowMajorMatrix::::rand(&mut OsRng, 70, 8)); + let medium_mat_dims = (0..5).map(|_| Dimensions { height: 70, width: 8 }); + + // 6 mats with 8 rows, 8 columns + let small_mats = (0..6).map(|_| RowMajorMatrix::::rand(&mut OsRng, 8, 8)); + let small_mat_dims = (0..6).map(|_| Dimensions { height: 8, width: 8 }); + + let (commit, prover_data) = + mmcs.commit(large_mats.chain(medium_mats).chain(small_mats).collect_vec()); + + let commit: [_; DIGEST_SIZE] = commit.into(); + let commit = commit.map(|x| builder.eval(x)); + // open the 6th row of each matrix and verify + let (opened_values, proof) = mmcs.open_batch(6, &prover_data); + let opened_values = opened_values + .into_iter() + .map(|x| x.into_iter().map(|y| vec![builder.eval::, _>(y)]).collect()) + .collect(); + let index = builder.eval(F::from_canonical_u32(6)); + let index_bits = C::num2bits(&mut builder, index, 32); + let proof = proof.into_iter().map(|p| p.map(|x| builder.eval(x))).collect(); + verify_batch::<_, SC>( + &mut builder, + commit, + large_mat_dims.chain(medium_mat_dims).chain(small_mat_dims).collect_vec(), + index_bits, + opened_values, + proof, + ); + } + + #[test] + fn test_fri_verify_shape_and_sample_challenges() { + let mut rng = &mut OsRng; + let log_degrees = &[16, 9, 7, 4, 2]; + let perm = inner_perm(); + let fri_config = inner_fri_config(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm.clone()); + let val_mmcs = InnerValMmcs::new(hash, compress); + let dft = InnerDft {}; + let pcs: InnerPcs = + InnerPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); + + // Generate proof. + let domains_and_polys = log_degrees + .iter() + .map(|&d| { + ( + >::natural_domain_for_degree( + &pcs, + 1 << d, + ), + RowMajorMatrix::::rand(&mut rng, 1 << d, 10), + ) + }) + .collect::>(); + let (commit, data) = >::commit( + &pcs, + domains_and_polys.clone(), + ); + let mut challenger = InnerChallenger::new(perm.clone()); + challenger.observe(commit); + let zeta = challenger.sample_ext_element::(); + let points = repeat_with(|| vec![zeta]).take(domains_and_polys.len()).collect::>(); + let (_, proof) = pcs.open(vec![(&data, points)], &mut challenger); + + // Verify proof. + let mut challenger = InnerChallenger::new(perm.clone()); + challenger.observe(commit); + let _: InnerChallenge = challenger.sample(); + let fri_challenges_gt = verifier::verify_shape_and_sample_challenges( + &inner_fri_config(), + &proof.fri_proof, + &mut challenger, + ) + .unwrap(); + + // Define circuit. + let mut builder = Builder::::default(); + let config = inner_fri_config(); + let fri_proof = const_fri_proof(&mut builder, proof.fri_proof); + + let mut challenger = DuplexChallengerVariable::new(&mut builder); + let commit: [_; DIGEST_SIZE] = commit.into(); + let commit: [Felt; DIGEST_SIZE] = commit.map(|x| builder.eval(x)); + challenger.observe_slice(&mut builder, commit); + let _ = challenger.sample_ext(&mut builder); + let fri_challenges = verify_shape_and_sample_challenges::( + &mut builder, + &config, + &fri_proof, + &mut challenger, + ); + + for i in 0..fri_challenges_gt.betas.len() { + builder.assert_ext_eq( + SymbolicExt::from_f(fri_challenges_gt.betas[i]), + fri_challenges.betas[i], + ); + } + + for i in 0..fri_challenges_gt.query_indices.len() { + let query_indices = + C::bits2num(&mut builder, fri_challenges.query_indices[i].iter().cloned()); + builder.assert_felt_eq( + F::from_canonical_usize(fri_challenges_gt.query_indices[i]), + query_indices, + ); + } + + run_test_recursion(builder.operations, None); + } + + #[test] + fn test_verify_two_adic_pcs_inner() { + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let log_degrees = &[19, 19]; + let perm = inner_perm(); + let fri_config = inner_fri_config(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm.clone()); + let val_mmcs = InnerValMmcs::new(hash, compress); + let dft = InnerDft {}; + let pcs: InnerPcs = + InnerPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); + + // Generate proof. + let domains_and_polys = log_degrees + .iter() + .map(|&d| { + ( + >::natural_domain_for_degree( + &pcs, + 1 << d, + ), + RowMajorMatrix::::rand(&mut rng, 1 << d, 100), + ) + }) + .collect::>(); + let (commit, data) = >::commit( + &pcs, + domains_and_polys.clone(), + ); + let mut challenger = InnerChallenger::new(perm.clone()); + challenger.observe(commit); + let zeta = challenger.sample_ext_element::(); + let points = domains_and_polys.iter().map(|_| vec![zeta]).collect::>(); + let (opening, proof) = pcs.open(vec![(&data, points)], &mut challenger); + + // Verify proof. + let mut challenger = InnerChallenger::new(perm.clone()); + challenger.observe(commit); + let x1 = challenger.sample_ext_element::(); + let os = domains_and_polys + .iter() + .zip(&opening[0]) + .map(|((domain, _), mat_openings)| (*domain, vec![(zeta, mat_openings[0].clone())])) + .collect::>(); + pcs.verify(vec![(commit, os.clone())], &proof, &mut challenger).unwrap(); + + // Define circuit. + let mut builder = Builder::::default(); + let config = inner_fri_config(); + let proof = const_two_adic_pcs_proof(&mut builder, proof); + let (commit, rounds) = const_two_adic_pcs_rounds(&mut builder, commit.into(), os); + let mut challenger = DuplexChallengerVariable::new(&mut builder); + challenger.observe_slice(&mut builder, commit); + let x2 = challenger.sample_ext(&mut builder); + let x1: Ext<_, _> = builder.constant(x1); + builder.assert_ext_eq(x1, x2); + verify_two_adic_pcs::<_, BabyBearPoseidon2>( + &mut builder, + &config, + &proof, + &mut challenger, + rounds, + ); + + run_test_recursion(builder.operations, std::iter::empty()); + } +} diff --git a/crates/recursion/circuit-v2/src/hash.rs b/crates/recursion/circuit-v2/src/hash.rs new file mode 100644 index 0000000000..4e99a220bc --- /dev/null +++ b/crates/recursion/circuit-v2/src/hash.rs @@ -0,0 +1,126 @@ +use std::iter::zip; + +use itertools::Itertools; +use p3_baby_bear::BabyBear; +use p3_field::{AbstractField, Field}; + +use p3_bn254_fr::Bn254Fr; +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + ir::{Builder, Config, DslIr, Felt, Var}, +}; +use sp1_recursion_core_v2::{stark::config::BabyBearPoseidon2Outer, DIGEST_SIZE}; +use sp1_stark::baby_bear_poseidon2::BabyBearPoseidon2; + +use crate::{ + challenger::{reduce_32, RATE, SPONGE_SIZE}, + select_chain, CircuitConfig, +}; + +pub trait FieldHasherVariable { + type Digest: Clone + Copy; + + fn hash(builder: &mut Builder, input: &[Felt]) -> Self::Digest; + + fn compress(builder: &mut Builder, input: [Self::Digest; 2]) -> Self::Digest; + + fn assert_digest_eq(builder: &mut Builder, a: Self::Digest, b: Self::Digest); + + // Encountered many issues trying to make the following two parametrically polymorphic. + fn select_chain_digest( + builder: &mut Builder, + should_swap: C::Bit, + input: [Self::Digest; 2], + ) -> [Self::Digest; 2]; +} + +impl>> FieldHasherVariable + for BabyBearPoseidon2 +{ + type Digest = [Felt; DIGEST_SIZE]; + + fn hash(builder: &mut Builder, input: &[Felt<::F>]) -> Self::Digest { + builder.poseidon2_hash_v2(input) + } + + fn compress(builder: &mut Builder, input: [Self::Digest; 2]) -> Self::Digest { + builder.poseidon2_compress_v2(input.into_iter().flatten()) + } + + fn assert_digest_eq(builder: &mut Builder, a: Self::Digest, b: Self::Digest) { + zip(a, b).for_each(|(e1, e2)| builder.assert_felt_eq(e1, e2)); + } + + fn select_chain_digest( + builder: &mut Builder, + should_swap: ::Bit, + input: [Self::Digest; 2], + ) -> [Self::Digest; 2] { + let err_msg = "select_chain's return value should have length the sum of its inputs"; + let mut selected = select_chain(builder, should_swap, input[0], input[1]); + let ret = [ + core::array::from_fn(|_| selected.next().expect(err_msg)), + core::array::from_fn(|_| selected.next().expect(err_msg)), + ]; + assert_eq!(selected.next(), None, "{}", err_msg); + ret + } +} + +pub const BN254_DIGEST_SIZE: usize = 1; +impl>> FieldHasherVariable + for BabyBearPoseidon2Outer +{ + type Digest = [Var; BN254_DIGEST_SIZE]; + + fn hash(builder: &mut Builder, input: &[Felt<::F>]) -> Self::Digest { + assert!(C::N::bits() == p3_bn254_fr::Bn254Fr::bits()); + assert!(C::F::bits() == p3_baby_bear::BabyBear::bits()); + let num_f_elms = C::N::bits() / C::F::bits(); + let mut state: [Var; SPONGE_SIZE] = + [builder.eval(C::N::zero()), builder.eval(C::N::zero()), builder.eval(C::N::zero())]; + for block_chunk in &input.iter().chunks(RATE) { + for (chunk_id, chunk) in (&block_chunk.chunks(num_f_elms)).into_iter().enumerate() { + let chunk = chunk.collect_vec().into_iter().copied().collect::>(); + state[chunk_id] = reduce_32(builder, chunk.as_slice()); + } + builder.push(DslIr::CircuitPoseidon2Permute(state)) + } + + [state[0]; BN254_DIGEST_SIZE] + } + + fn compress(builder: &mut Builder, input: [Self::Digest; 2]) -> Self::Digest { + let state: [Var; SPONGE_SIZE] = + [builder.eval(input[0][0]), builder.eval(input[1][0]), builder.eval(C::N::zero())]; + builder.push(DslIr::CircuitPoseidon2Permute(state)); + [state[0]; BN254_DIGEST_SIZE] + } + + fn assert_digest_eq(builder: &mut Builder, a: Self::Digest, b: Self::Digest) { + zip(a, b).for_each(|(e1, e2)| builder.assert_var_eq(e1, e2)); + } + + fn select_chain_digest( + builder: &mut Builder, + should_swap: ::Bit, + input: [Self::Digest; 2], + ) -> [Self::Digest; 2] { + let result0: [Var<_>; 1] = core::array::from_fn(|j| { + let result = builder.uninit(); + builder.push(DslIr::CircuitSelectV(should_swap, input[1][j], input[0][j], result)); + result + }); + let result1: [Var<_>; 1] = core::array::from_fn(|j| { + let result = builder.uninit(); + builder.push(DslIr::CircuitSelectV(should_swap, input[0][j], input[1][j], result)); + result + }); + + [result0, result1] + } +} + +// impl> FieldHasherVariable for OuterHash { + +// } diff --git a/crates/recursion/circuit-v2/src/lib.rs b/crates/recursion/circuit-v2/src/lib.rs new file mode 100644 index 0000000000..c3aedb819f --- /dev/null +++ b/crates/recursion/circuit-v2/src/lib.rs @@ -0,0 +1,353 @@ +//! Copied from [`sp1_recursion_program`]. + +use std::{ + iter::{repeat, zip}, + ops::{Add, Mul}, +}; + +use challenger::{ + CanCopyChallenger, CanObserveVariable, DuplexChallengerVariable, FieldChallengerVariable, + MultiField32ChallengerVariable, +}; +use hash::FieldHasherVariable; +use p3_bn254_fr::Bn254Fr; +use p3_field::AbstractField; +use p3_matrix::dense::RowMajorMatrix; +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + config::{InnerConfig, OuterConfig}, + ir::{Builder, Config, DslIr, Ext, Felt, Var, Variable}, +}; + +mod types; + +pub mod build_wrap_v2; +pub mod challenger; +pub mod constraints; +pub mod domain; +pub mod fri; +pub mod hash; +pub mod machine; +pub mod stark; +pub(crate) mod utils; +pub mod witness; + +use sp1_stark::{ + baby_bear_poseidon2::{BabyBearPoseidon2, ValMmcs}, + StarkGenericConfig, +}; +pub use types::*; + +use p3_challenger::{CanObserve, CanSample, FieldChallenger, GrindingChallenger}; +use p3_commit::{ExtensionMmcs, Mmcs}; +use p3_dft::Radix2DitParallel; +use p3_fri::{FriConfig, TwoAdicFriPcs}; +use sp1_recursion_core_v2::{ + stark::config::{BabyBearPoseidon2Outer, OuterValMmcs}, + D, +}; + +use p3_baby_bear::BabyBear; + +type EF = ::Challenge; + +pub type PcsConfig = FriConfig< + ExtensionMmcs< + ::Val, + ::Challenge, + ::ValMmcs, + >, +>; + +pub type Digest = >::Digest; + +pub type FriMmcs = ExtensionMmcs::ValMmcs>; + +pub trait BabyBearFriConfig: + StarkGenericConfig< + Val = BabyBear, + Challenge = EF, + Challenger = Self::FriChallenger, + Pcs = TwoAdicFriPcs< + BabyBear, + Radix2DitParallel, + Self::ValMmcs, + ExtensionMmcs, + >, +> +{ + type ValMmcs: Mmcs> = Self::RowMajorProverData> + + Send + + Sync; + type RowMajorProverData: Clone + Send + Sync; + type FriChallenger: CanObserve<>::Commitment> + + CanSample + + GrindingChallenger + + FieldChallenger; + + fn fri_config(&self) -> &FriConfig>; +} + +pub trait BabyBearFriConfigVariable>: + BabyBearFriConfig + FieldHasherVariable +{ + type FriChallengerVariable: FieldChallengerVariable::Bit> + + CanObserveVariable>::Digest> + + CanCopyChallenger; + + /// Get a new challenger corresponding to the given config. + fn challenger_variable(&self, builder: &mut Builder) -> Self::FriChallengerVariable; +} + +pub trait CircuitConfig: Config { + type Bit: Clone + Variable; + + fn read_bit(builder: &mut Builder) -> Self::Bit; + + fn read_felt(builder: &mut Builder) -> Felt; + + fn read_ext(builder: &mut Builder) -> Ext; + + fn ext2felt( + builder: &mut Builder, + ext: Ext<::F, ::EF>, + ) -> [Felt<::F>; D]; + + fn exp_reverse_bits( + builder: &mut Builder, + input: Felt<::F>, + power_bits: Vec, + ) -> Felt<::F>; + + fn num2bits( + builder: &mut Builder, + num: Felt<::F>, + num_bits: usize, + ) -> Vec; + + fn bits2num( + builder: &mut Builder, + bits: impl IntoIterator, + ) -> Felt<::F>; + + #[allow(clippy::type_complexity)] + fn select_chain_ef( + builder: &mut Builder, + should_swap: Self::Bit, + first: impl IntoIterator::F, ::EF>> + Clone, + second: impl IntoIterator::F, ::EF>> + Clone, + ) -> Vec::F, ::EF>>; +} + +impl CircuitConfig for InnerConfig { + type Bit = Felt<::F>; + + fn read_bit(builder: &mut Builder) -> Self::Bit { + builder.hint_felt_v2() + } + + fn read_felt(builder: &mut Builder) -> Felt { + builder.hint_felt_v2() + } + + fn read_ext(builder: &mut Builder) -> Ext { + builder.hint_ext_v2() + } + + fn ext2felt( + builder: &mut Builder, + ext: Ext<::F, ::EF>, + ) -> [Felt<::F>; D] { + builder.ext2felt_v2(ext) + } + + fn exp_reverse_bits( + builder: &mut Builder, + input: Felt<::F>, + power_bits: Vec::F>>, + ) -> Felt<::F> { + builder.exp_reverse_bits_v2(input, power_bits) + } + + fn num2bits( + builder: &mut Builder, + num: Felt<::F>, + num_bits: usize, + ) -> Vec::F>> { + builder.num2bits_v2_f(num, num_bits) + } + + fn bits2num( + builder: &mut Builder, + bits: impl IntoIterator::F>>, + ) -> Felt<::F> { + builder.bits2num_v2_f(bits) + } + + fn select_chain_ef( + builder: &mut Builder, + should_swap: Self::Bit, + first: impl IntoIterator::F, ::EF>> + Clone, + second: impl IntoIterator::F, ::EF>> + Clone, + ) -> Vec::F, ::EF>> { + let one: Felt<_> = builder.constant(Self::F::one()); + let shouldnt_swap: Felt<_> = builder.eval(one - should_swap); + + let id_branch = first.clone().into_iter().chain(second.clone()); + let swap_branch = second.into_iter().chain(first); + zip(zip(id_branch, swap_branch), zip(repeat(shouldnt_swap), repeat(should_swap))) + .map(|((id_v, sw_v), (id_c, sw_c))| builder.eval(id_v * id_c + sw_v * sw_c)) + .collect() + } +} + +impl CircuitConfig for OuterConfig { + type Bit = Var<::N>; + + fn read_bit(builder: &mut Builder) -> Self::Bit { + builder.witness_var() + } + + fn read_felt(builder: &mut Builder) -> Felt { + builder.witness_felt() + } + + fn read_ext(builder: &mut Builder) -> Ext { + builder.witness_ext() + } + + fn ext2felt( + builder: &mut Builder, + ext: Ext<::F, ::EF>, + ) -> [Felt<::F>; D] { + let felts = core::array::from_fn(|_| builder.uninit()); + builder.operations.push(DslIr::CircuitExt2Felt(felts, ext)); + felts + } + + fn exp_reverse_bits( + builder: &mut Builder, + input: Felt<::F>, + power_bits: Vec::N>>, + ) -> Felt<::F> { + let mut result = builder.constant(Self::F::one()); + let power_f = input; + let bit_len = power_bits.len(); + + for i in 1..=bit_len { + let index = bit_len - i; + let bit = power_bits[index]; + let prod = builder.eval(result * power_f); + result = builder.select_f(bit, prod, result); + builder.assign(power_f, power_f * power_f); + } + result + } + + fn num2bits( + builder: &mut Builder, + num: Felt<::F>, + num_bits: usize, + ) -> Vec::N>> { + builder.num2bits_f_circuit(num)[..num_bits].to_vec() + } + + fn bits2num( + builder: &mut Builder, + bits: impl IntoIterator::N>>, + ) -> Felt<::F> { + let result = builder.eval(Self::F::zero()); + for (i, bit) in bits.into_iter().enumerate() { + let to_add: Felt<_> = builder.uninit(); + let pow2 = builder.constant(Self::F::from_canonical_u32(1 << i)); + let zero = builder.constant(Self::F::zero()); + builder.operations.push(DslIr::CircuitSelectF(bit, pow2, zero, to_add)); + builder.assign(result, result + to_add); + } + result + } + + fn select_chain_ef( + builder: &mut Builder, + should_swap: Self::Bit, + first: impl IntoIterator::F, ::EF>> + Clone, + second: impl IntoIterator::F, ::EF>> + Clone, + ) -> Vec::F, ::EF>> { + let id_branch = first.clone().into_iter().chain(second.clone()); + let swap_branch = second.into_iter().chain(first); + zip(id_branch, swap_branch) + .map(|(id_v, sw_v): (Ext<_, _>, Ext<_, _>)| -> Ext<_, _> { + let result: Ext<_, _> = builder.uninit(); + builder.operations.push(DslIr::CircuitSelectE(should_swap, sw_v, id_v, result)); + result + }) + .collect() + } +} + +impl BabyBearFriConfig for BabyBearPoseidon2 { + type ValMmcs = ValMmcs; + type FriChallenger = ::Challenger; + type RowMajorProverData = >::ProverData>; + + fn fri_config(&self) -> &FriConfig> { + self.pcs().fri_config() + } +} + +impl BabyBearFriConfig for BabyBearPoseidon2Outer { + type ValMmcs = OuterValMmcs; + type FriChallenger = ::Challenger; + + type RowMajorProverData = + >::ProverData>; + + fn fri_config(&self) -> &FriConfig> { + self.pcs().fri_config() + } +} + +impl>> BabyBearFriConfigVariable + for BabyBearPoseidon2 +{ + type FriChallengerVariable = DuplexChallengerVariable; + + fn challenger_variable(&self, builder: &mut Builder) -> Self::FriChallengerVariable { + DuplexChallengerVariable::new(builder) + } +} + +impl>> BabyBearFriConfigVariable + for BabyBearPoseidon2Outer +{ + type FriChallengerVariable = MultiField32ChallengerVariable; + + fn challenger_variable(&self, builder: &mut Builder) -> Self::FriChallengerVariable { + MultiField32ChallengerVariable::new(builder) + } +} + +pub fn select_chain<'a, C, R, S>( + builder: &'a mut Builder, + should_swap: R, + first: impl IntoIterator + Clone + 'a, + second: impl IntoIterator + Clone + 'a, +) -> impl Iterator + 'a +where + C: Config, + R: Variable + 'a, + S: Variable + 'a, + >::Expression: AbstractField + + Mul<>::Expression, Output = >::Expression>, + >::Expression: Add>::Expression>, +{ + let should_swap: >::Expression = should_swap.into(); + let one = >::Expression::one(); + let shouldnt_swap = one - should_swap.clone(); + + let id_branch = + first.clone().into_iter().chain(second.clone()).map(>::Expression::from); + let swap_branch = second.into_iter().chain(first).map(>::Expression::from); + zip(zip(id_branch, swap_branch), zip(repeat(shouldnt_swap), repeat(should_swap))) + .map(|((id_v, sw_v), (id_c, sw_c))| builder.eval(id_c * id_v + sw_c * sw_v)) +} diff --git a/crates/recursion/circuit-v2/src/machine/compress.rs b/crates/recursion/circuit-v2/src/machine/compress.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/recursion/circuit-v2/src/machine/compress.rs @@ -0,0 +1 @@ + diff --git a/crates/recursion/circuit-v2/src/machine/core.rs b/crates/recursion/circuit-v2/src/machine/core.rs new file mode 100644 index 0000000000..32d62cc2ca --- /dev/null +++ b/crates/recursion/circuit-v2/src/machine/core.rs @@ -0,0 +1,558 @@ +use std::{ + array, + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; + +use itertools::Itertools; +use p3_baby_bear::BabyBear; +use p3_commit::Mmcs; +use p3_field::AbstractField; +use p3_matrix::dense::RowMajorMatrix; +use sp1_core_machine::riscv::RiscvAir; +use sp1_primitives::consts::WORD_SIZE; +use sp1_recursion_core_v2::air::PV_DIGEST_NUM_WORDS; +use sp1_stark::{ + air::{PublicValues, POSEIDON_NUM_WORDS}, + StarkMachine, Word, +}; + +use crate::{ + utils::commit_recursion_public_values, BabyBearFriConfig, BabyBearFriConfigVariable, + CircuitConfig, +}; + +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + ir::{Builder, Config, Ext, ExtConst, Felt}, +}; + +use sp1_recursion_core_v2::{ + air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}, + DIGEST_SIZE, +}; + +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable}, + stark::{ShardProofVariable, StarkVerifier}, + VerifyingKeyVariable, +}; + +pub struct SP1RecursionWitnessVariable< + C: CircuitConfig, + SC: BabyBearFriConfigVariable, +> { + pub vk: VerifyingKeyVariable, + pub shard_proofs: Vec>, + pub leaf_challenger: SC::FriChallengerVariable, + pub initial_reconstruct_challenger: DuplexChallengerVariable, + pub is_complete: Felt, +} + +/// A program for recursively verifying a batch of SP1 proofs. +#[derive(Debug, Clone, Copy)] +pub struct SP1RecursiveVerifier { + _phantom: PhantomData<(C, SC)>, +} + +impl SP1RecursiveVerifier +where + SC: BabyBearFriConfigVariable< + C, + FriChallengerVariable = DuplexChallengerVariable, + Digest = [Felt; DIGEST_SIZE], + >, + C: CircuitConfig>, + >::ProverData>: Clone, +{ + /// Verify a batch of SP1 shard proofs and aggregate their public values. + /// + /// This program represents a first recursive step in the verification of an SP1 proof + /// consisting of one or more shards. Each shard proof is verified and its public values are + /// aggregated into a single set representing the start and end state of the program execution + /// across all shards. + /// + /// # Constraints + /// + /// ## Verifying the STARK proofs. + /// For each shard, the verifier asserts the correctness of the STARK proof which is composed + /// of verifying the FRI proof for openings and verifying the constraints. + /// + /// ## Aggregating the shard public values. + /// See [SP1Prover::verify] for the verification algorithm of a complete SP1 proof. In this + /// function, we are aggregating several shard proofs and attesting to an aggregated state which + /// represents all the shards. + /// + /// ## The leaf challenger. + /// A key difference between the recursive tree verification and the complete one in + /// [SP1Prover::verify] is that the recursive verifier has no way of reconstructing the + /// chanllenger only from a part of the shard proof. Therefore, the value of the leaf challenger + /// is witnessed in the program and the verifier asserts correctness given this challenger. + /// In the course of the recursive verification, the challenger is reconstructed by observing + /// the commitments one by one, and in the final step, the challenger is asserted to be the same + /// as the one witnessed here. + pub fn verify( + builder: &mut Builder, + machine: &StarkMachine>, + input: SP1RecursionWitnessVariable, + ) { + // Read input. + let SP1RecursionWitnessVariable { + vk, + shard_proofs, + leaf_challenger, + initial_reconstruct_challenger, + is_complete, + } = input; + + // Initialize shard variables. + let initial_shard: Felt<_> = builder.uninit(); + let current_shard: Felt<_> = builder.uninit(); + + // Initialize execution shard variables. + let initial_execution_shard: Felt<_> = builder.uninit(); + let current_execution_shard: Felt<_> = builder.uninit(); + + // Initialize program counter variables. + let start_pc: Felt<_> = builder.uninit(); + let current_pc: Felt<_> = builder.uninit(); + + // Initialize memory initialization and finalization variables. + let initial_previous_init_addr_bits: [Felt<_>; 32] = array::from_fn(|_| builder.uninit()); + let initial_previous_finalize_addr_bits: [Felt<_>; 32] = + array::from_fn(|_| builder.uninit()); + let current_init_addr_bits: [Felt<_>; 32] = array::from_fn(|_| builder.uninit()); + let current_finalize_addr_bits: [Felt<_>; 32] = array::from_fn(|_| builder.uninit()); + + // Initialize the exit code variable. + let exit_code: Felt<_> = builder.uninit(); + + // Initialize the public values digest. + let committed_value_digest: [Word>; PV_DIGEST_NUM_WORDS] = + array::from_fn(|_| Word(array::from_fn(|_| builder.uninit()))); + + // Initialize the deferred proofs digest. + let deferred_proofs_digest: [Felt<_>; POSEIDON_NUM_WORDS] = + array::from_fn(|_| builder.uninit()); + + // Initialize the challenger variables. + let leaf_challenger_public_values = leaf_challenger.public_values(builder); + let mut reconstruct_challenger: DuplexChallengerVariable<_> = + initial_reconstruct_challenger.copy(builder); + + // Initialize the cumulative sum. + let cumulative_sum: Ext<_, _> = builder.eval(C::EF::zero().cons()); + + // Assert that the number of proofs is not zero. + assert!(!shard_proofs.is_empty()); + + // Verify proofs. + for (i, shard_proof) in shard_proofs.into_iter().enumerate() { + let contains_cpu = shard_proof.contains_cpu(); + let _contains_memory_init = shard_proof.contains_memory_init(); + let _contains_memory_finalize = shard_proof.contains_memory_finalize(); + + // Get the public values. + let public_values: &PublicValues>, Felt<_>> = + shard_proof.public_values.as_slice().borrow(); + + let _shard = public_values.shard; + + // If this is the first proof in the batch, initialize the variables. + if i == 0 { + // Shard. + builder.assign(initial_shard, public_values.shard); + builder.assign(current_shard, public_values.shard); + + // Execution shard. + builder.assign(initial_execution_shard, public_values.execution_shard); + builder.assign(current_execution_shard, public_values.execution_shard); + + // Program counter. + builder.assign(start_pc, public_values.start_pc); + builder.assign(current_pc, public_values.start_pc); + + // Memory initialization & finalization. + for ((bit, pub_bit), first_bit) in current_init_addr_bits + .iter() + .zip(public_values.previous_init_addr_bits.iter()) + .zip(initial_previous_init_addr_bits.iter()) + { + builder.assign(*bit, *pub_bit); + builder.assign(*first_bit, *pub_bit); + } + for ((bit, pub_bit), first_bit) in current_finalize_addr_bits + .iter() + .zip(public_values.previous_finalize_addr_bits.iter()) + .zip(initial_previous_finalize_addr_bits.iter()) + { + builder.assign(*bit, *pub_bit); + builder.assign(*first_bit, *pub_bit); + } + + // Exit code. + builder.assign(exit_code, public_values.exit_code); + + // Commited public values digests. + for (word, first_word) in committed_value_digest + .iter() + .zip_eq(public_values.committed_value_digest.iter()) + { + for (byte, first_byte) in word.0.iter().zip_eq(first_word.0.iter()) { + builder.assign(*byte, *first_byte); + } + } + + // Deferred proofs digests. + for (digest, first_digest) in deferred_proofs_digest + .iter() + .zip_eq(public_values.deferred_proofs_digest.iter()) + { + builder.assign(*digest, *first_digest); + } + } + + // // If the shard is the first shard, assert that the initial challenger is equal to a + // // fresh challenger observing the verifier key and the initial pc. + // let shard = felt2var(builder, public_values.shard); + // builder.if_eq(shard, C::N::one()).then(|builder| { + // let mut first_initial_challenger = DuplexChallengerVariable::new(builder); + // first_initial_challenger.observe(builder, vk.commitment.clone()); + // first_initial_challenger.observe(builder, vk.pc_start); + // initial_reconstruct_challenger.assert_eq(builder, &first_initial_challenger); + // }); + + // Verify the shard. + // + // Do not verify the cumulative sum here, since the permutation challenge is shared + // between all shards. + let mut challenger = leaf_challenger.copy(builder); + StarkVerifier::::verify_shard( + builder, + &vk, + machine, + &mut challenger, + &shard_proof, + ); + + // // First shard has a "CPU" constraint. + // { + // builder.if_eq(shard, C::N::one()).then(|builder| { + // builder.assert_var_eq(contains_cpu, C::N::one()); + // }); + // } + + // // CPU log degree bound check constraints. + // { + // for (i, chip) in machine.chips().iter().enumerate() { + // if chip.name() == "CPU" { + // builder.if_eq(contains_cpu, C::N::one()).then(|builder| { + // let index = builder.get(&proof.sorted_idxs, i); + // let cpu_log_degree = + // builder.get(&proof.opened_values.chips, index).log_degree; + // let cpu_log_degree_lt_max: Var<_> = builder.eval(C::N::zero()); + // builder + // .range(0, MAX_CPU_LOG_DEGREE + 1) + // .for_each(|j, builder| { + // builder.if_eq(j, cpu_log_degree).then(|builder| { + // builder.assign(cpu_log_degree_lt_max, C::N::one()); + // }); + // }); + // builder.assert_var_eq(cpu_log_degree_lt_max, C::N::one()); + // }); + // } + // } + // } + + // Shard constraints. + { + // Assert that the shard of the proof is equal to the current shard. + builder.assert_felt_eq(current_shard, public_values.shard); + + // Increment the current shard by one. + builder.assign(current_shard, current_shard + C::F::one()); + } + + // Execution shard constraints. + // let execution_shard = felt2var(builder, public_values.execution_shard); + { + // If the shard has a "CPU" chip, then the execution shard should be incremented by + // 1. + if contains_cpu { + // Assert that the shard of the proof is equal to the current shard. + // builder.assert_felt_eq(current_execution_shard, + // public_values.execution_shard); + + builder.assign(current_execution_shard, current_execution_shard + C::F::one()); + } + } + + // Program counter constraints. + { + // // If it's the first shard (which is the first execution shard), then the + // start_pc // should be vk.pc_start. + // builder.if_eq(shard, C::N::one()).then(|builder| { + // builder.assert_felt_eq(public_values.start_pc, vk.pc_start); + // }); + + // // Assert that the start_pc of the proof is equal to the current pc. + // builder.assert_felt_eq(current_pc, public_values.start_pc); + + // // If it's not a shard with "CPU", then assert that the start_pc equals the + // next_pc. builder.if_ne(contains_cpu, C::N::one()).then(|builder| + // { builder.assert_felt_eq(public_values.start_pc, + // public_values.next_pc); }); + + // // If it's a shard with "CPU", then assert that the start_pc is not zero. + // builder.if_eq(contains_cpu, C::N::one()).then(|builder| { + // builder.assert_felt_ne(public_values.start_pc, C::F::zero()); + // }); + + // Update current_pc to be the end_pc of the current proof. + builder.assign(current_pc, public_values.next_pc); + } + + // Exit code constraints. + { + // Assert that the exit code is zero (success) for all proofs. + builder.assert_felt_eq(exit_code, C::F::zero()); + } + + // Memory initialization & finalization constraints. + { + // // Assert that `init_addr_bits` and `finalize_addr_bits` are zero for the first + // execution shard. builder.if_eq(execution_shard, + // C::N::one()).then(|builder| { // Assert that the + // MemoryInitialize address bits are zero. for bit in + // current_init_addr_bits.iter() { builder.assert_felt_eq(* + // bit, C::F::zero()); } + + // // Assert that the MemoryFinalize address bits are zero. + // for bit in current_finalize_addr_bits.iter() { + // builder.assert_felt_eq(*bit, C::F::zero()); + // } + // }); + + // // Assert that the MemoryInitialize address bits match the current loop variable. + // for (bit, current_bit) in current_init_addr_bits + // .iter() + // .zip_eq(public_values.previous_init_addr_bits.iter()) + // { + // builder.assert_felt_eq(*bit, *current_bit); + // } + + // // Assert that the MemoryFinalize address bits match the current loop variable. + // for (bit, current_bit) in current_finalize_addr_bits + // .iter() + // .zip_eq(public_values.previous_finalize_addr_bits.iter()) + // { + // builder.assert_felt_eq(*bit, *current_bit); + // } + + // // Assert that if MemoryInit is not present, then the address bits are the same. + // builder + // .if_ne(contains_memory_init, C::N::one()) + // .then(|builder| { + // for (prev_bit, last_bit) in public_values + // .previous_init_addr_bits + // .iter() + // .zip_eq(public_values.last_init_addr_bits.iter()) + // { + // builder.assert_felt_eq(*prev_bit, *last_bit); + // } + // }); + + // // Assert that if MemoryFinalize is not present, then the address bits are the + // same. builder + // .if_ne(contains_memory_finalize, C::N::one()) + // .then(|builder| { + // for (prev_bit, last_bit) in public_values + // .previous_finalize_addr_bits + // .iter() + // .zip_eq(public_values.last_finalize_addr_bits.iter()) + // { + // builder.assert_felt_eq(*prev_bit, *last_bit); + // } + // }); + + // Update the MemoryInitialize address bits. + for (bit, pub_bit) in + current_init_addr_bits.iter().zip(public_values.last_init_addr_bits.iter()) + { + builder.assign(*bit, *pub_bit); + } + + // Update the MemoryFinalize address bits. + for (bit, pub_bit) in current_finalize_addr_bits + .iter() + .zip(public_values.last_finalize_addr_bits.iter()) + { + builder.assign(*bit, *pub_bit); + } + } + + // Digest constraints. + { + // // If `commited_value_digest` is not zero, then + // `public_values.commited_value_digest // should be the current + // value. let is_zero: Var<_> = builder.eval(C::N::one()); + // #[allow(clippy::needless_range_loop)] + // for i in 0..committed_value_digest.len() { + // for j in 0..WORD_SIZE { + // let d = felt2var(builder, committed_value_digest[i][j]); + // builder.if_ne(d, C::N::zero()).then(|builder| { + // builder.assign(is_zero, C::N::zero()); + // }); + // } + // } + // builder.if_eq(is_zero, C::N::zero()).then(|builder| { + // #[allow(clippy::needless_range_loop)] + // for i in 0..committed_value_digest.len() { + // for j in 0..WORD_SIZE { + // builder.assert_felt_eq( + // committed_value_digest[i][j], + // public_values.committed_value_digest[i][j], + // ); + // } + // } + // }); + + // // If it's not a shard with "CPU", then the committed value digest should not + // change. builder.if_ne(contains_cpu, C::N::one()).then(|builder| { + // #[allow(clippy::needless_range_loop)] + // for i in 0..committed_value_digest.len() { + // for j in 0..WORD_SIZE { + // builder.assert_felt_eq( + // committed_value_digest[i][j], + // public_values.committed_value_digest[i][j], + // ); + // } + // } + // }); + + // Update the committed value digest. + #[allow(clippy::needless_range_loop)] + for i in 0..committed_value_digest.len() { + for j in 0..WORD_SIZE { + builder.assign( + committed_value_digest[i][j], + public_values.committed_value_digest[i][j], + ); + } + } + + // // If `deferred_proofs_digest` is not zero, then + // `public_values.deferred_proofs_digest // should be the current + // value. let is_zero: Var<_> = builder.eval(C::N::one()); + // #[allow(clippy::needless_range_loop)] + // for i in 0..deferred_proofs_digest.len() { + // let d = felt2var(builder, deferred_proofs_digest[i]); + // builder.if_ne(d, C::N::zero()).then(|builder| { + // builder.assign(is_zero, C::N::zero()); + // }); + // } + // builder.if_eq(is_zero, C::N::zero()).then(|builder| { + // #[allow(clippy::needless_range_loop)] + // for i in 0..deferred_proofs_digest.len() { + // builder.assert_felt_eq( + // deferred_proofs_digest[i], + // public_values.deferred_proofs_digest[i], + // ); + // } + // }); + + // // If it's not a shard with "CPU", then the deferred proofs digest should not + // change. builder.if_ne(contains_cpu, C::N::one()).then(|builder| { + // #[allow(clippy::needless_range_loop)] + // for i in 0..deferred_proofs_digest.len() { + // builder.assert_felt_eq( + // deferred_proofs_digest[i], + // public_values.deferred_proofs_digest[i], + // ); + // } + // }); + + // Update the deferred proofs digest. + #[allow(clippy::needless_range_loop)] + for i in 0..deferred_proofs_digest.len() { + builder + .assign(deferred_proofs_digest[i], public_values.deferred_proofs_digest[i]); + } + } + + // // Verify that the number of shards is not too large. + // builder.range_check_f(public_values.shard, 16); + + // Update the reconstruct challenger. + reconstruct_challenger.observe(builder, shard_proof.commitment.main_commit); + for element in shard_proof.public_values.iter() { + reconstruct_challenger.observe(builder, *element); + } + + // Cumulative sum is updated by sums of all chips. + for values in shard_proof.opened_values.chips.iter() { + builder.assign(cumulative_sum, cumulative_sum + values.cumulative_sum); + } + } + + // Write all values to the public values struct and commit to them. + { + // Compute the vk digest. + let vk_digest = vk.hash(builder); + + // Collect the public values for challengers. + let initial_challenger_public_values = + initial_reconstruct_challenger.public_values(builder); + let final_challenger_public_values = reconstruct_challenger.public_values(builder); + + // Collect the cumulative sum. + let cumulative_sum_array = builder.ext2felt_v2(cumulative_sum); + + // Collect the deferred proof digests. + let zero: Felt<_> = builder.eval(C::F::zero()); + let start_deferred_digest = [zero; POSEIDON_NUM_WORDS]; + let end_deferred_digest = [zero; POSEIDON_NUM_WORDS]; + + // Collect the is_complete flag. + // let is_complete_felt = var2felt(builder, is_complete); + + // Initialize the public values we will commit to. + let mut recursion_public_values_stream = [zero; RECURSIVE_PROOF_NUM_PV_ELTS]; + let recursion_public_values: &mut RecursionPublicValues<_> = + recursion_public_values_stream.as_mut_slice().borrow_mut(); + recursion_public_values.committed_value_digest = committed_value_digest; + recursion_public_values.deferred_proofs_digest = deferred_proofs_digest; + recursion_public_values.start_pc = start_pc; + recursion_public_values.next_pc = current_pc; + recursion_public_values.start_shard = initial_shard; + recursion_public_values.next_shard = current_shard; + recursion_public_values.start_execution_shard = initial_execution_shard; + recursion_public_values.next_execution_shard = current_execution_shard; + recursion_public_values.previous_init_addr_bits = initial_previous_init_addr_bits; + recursion_public_values.last_init_addr_bits = current_init_addr_bits; + recursion_public_values.previous_finalize_addr_bits = + initial_previous_finalize_addr_bits; + recursion_public_values.last_finalize_addr_bits = current_finalize_addr_bits; + recursion_public_values.sp1_vk_digest = vk_digest; + recursion_public_values.leaf_challenger = leaf_challenger_public_values; + recursion_public_values.start_reconstruct_challenger = initial_challenger_public_values; + recursion_public_values.end_reconstruct_challenger = final_challenger_public_values; + recursion_public_values.cumulative_sum = cumulative_sum_array; + recursion_public_values.start_reconstruct_deferred_digest = start_deferred_digest; + recursion_public_values.end_reconstruct_deferred_digest = end_deferred_digest; + recursion_public_values.exit_code = exit_code; + recursion_public_values.is_complete = is_complete; + + // // If the proof represents a complete proof, make completeness assertions. + // // + // // *Remark*: In this program, this only happends if there is one shard and the + // program has // no deferred proofs to verify. However, the completeness + // check is independent of these // facts. + // builder.if_eq(is_complete, C::N::one()).then(|builder| { + // assert_complete(builder, recursion_public_values, &reconstruct_challenger) + // }); + + commit_recursion_public_values(builder, recursion_public_values); + } + } +} diff --git a/crates/recursion/circuit-v2/src/machine/mod.rs b/crates/recursion/circuit-v2/src/machine/mod.rs new file mode 100644 index 0000000000..8de8ec4a0f --- /dev/null +++ b/crates/recursion/circuit-v2/src/machine/mod.rs @@ -0,0 +1,14 @@ +mod compress; +mod core; +mod witness; + +#[allow(unused_imports)] +pub use compress::*; +pub use core::*; + +#[allow(unused_imports)] +pub use witness::*; + +pub use sp1_recursion_program::machine::{ + SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout, +}; diff --git a/crates/recursion/circuit-v2/src/machine/witness.rs b/crates/recursion/circuit-v2/src/machine/witness.rs new file mode 100644 index 0000000000..44f8ab54c7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/machine/witness.rs @@ -0,0 +1,111 @@ +use std::borrow::Borrow; + +use p3_baby_bear::BabyBear; +use p3_challenger::DuplexChallenger; +use p3_symmetric::Hash; + +use p3_field::AbstractField; +use sp1_recursion_compiler::ir::Builder; +use sp1_stark::{ + air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, InnerChallenge, InnerPerm, InnerVal, + StarkVerifyingKey, +}; + +use sp1_recursion_compiler::ir::Felt; + +use crate::{ + challenger::DuplexChallengerVariable, + witness::{WitnessWriter, Witnessable}, + CircuitConfig, VerifyingKeyVariable, +}; + +use super::{SP1RecursionMemoryLayout, SP1RecursionWitnessVariable}; + +impl Witnessable for DuplexChallenger +where + C: CircuitConfig, +{ + type WitnessVariable = DuplexChallengerVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let sponge_state = self.sponge_state.read(builder); + let input_buffer = self.input_buffer.read(builder); + let output_buffer = self.output_buffer.read(builder); + DuplexChallengerVariable { sponge_state, input_buffer, output_buffer } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.sponge_state.write(witness); + self.input_buffer.write(witness); + self.output_buffer.write(witness); + } +} + +impl Witnessable for Hash +where + C: CircuitConfig, + W: Witnessable, +{ + type WitnessVariable = [W::WitnessVariable; DIGEST_ELEMENTS]; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let array: &[W; DIGEST_ELEMENTS] = self.borrow(); + array.read(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + let array: &[W; DIGEST_ELEMENTS] = self.borrow(); + array.write(witness); + } +} + +impl Witnessable for StarkVerifyingKey +where + C: CircuitConfig>, +{ + type WitnessVariable = VerifyingKeyVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commitment = self.commit.read(builder); + let pc_start = self.pc_start.read(builder); + let chip_information = self.chip_information.clone(); + let chip_ordering = self.chip_ordering.clone(); + VerifyingKeyVariable { commitment, pc_start, chip_information, chip_ordering } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit.write(witness); + self.pc_start.write(witness); + } +} + +impl<'a, C, A> Witnessable for SP1RecursionMemoryLayout<'a, BabyBearPoseidon2, A> +where + C: CircuitConfig>, + A: MachineAir, +{ + type WitnessVariable = SP1RecursionWitnessVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let vk = self.vk.read(builder); + let shard_proofs = self.shard_proofs.read(builder); + let leaf_challenger = self.leaf_challenger.read(builder); + let initial_reconstruct_challenger = self.initial_reconstruct_challenger.read(builder); + let is_complete = InnerVal::from_bool(self.is_complete).read(builder); + SP1RecursionWitnessVariable { + vk, + shard_proofs, + leaf_challenger, + initial_reconstruct_challenger, + is_complete, + } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.vk.write(witness); + self.shard_proofs.write(witness); + self.leaf_challenger.write(witness); + self.initial_reconstruct_challenger.write(witness); + self.is_complete.write(witness); + } +} diff --git a/crates/recursion/circuit-v2/src/stark.rs b/crates/recursion/circuit-v2/src/stark.rs new file mode 100644 index 0000000000..9f0a07b107 --- /dev/null +++ b/crates/recursion/circuit-v2/src/stark.rs @@ -0,0 +1,361 @@ +use hashbrown::HashMap; +use itertools::{izip, Itertools}; +use p3_commit::Mmcs; +use p3_matrix::dense::RowMajorMatrix; + +use p3_air::Air; +use p3_baby_bear::BabyBear; +use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; +use p3_field::TwoAdicField; +use sp1_stark::{ShardCommitment, ShardOpenedValues, Val}; + +use p3_commit::PolynomialSpace; + +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + ir::{Builder, Config, Ext}, + prelude::Felt, +}; +use sp1_stark::{air::MachineAir, StarkGenericConfig, StarkMachine, StarkVerifyingKey}; + +use crate::{ + challenger::CanObserveVariable, CircuitConfig, TwoAdicPcsMatsVariable, TwoAdicPcsProofVariable, +}; + +use crate::{ + challenger::FieldChallengerVariable, constraints::RecursiveVerifierConstraintFolder, + domain::PolynomialSpaceVariable, fri::verify_two_adic_pcs, BabyBearFriConfigVariable, + TwoAdicPcsRoundVariable, VerifyingKeyVariable, +}; + +/// Reference: [sp1_core::stark::ShardProof] +#[derive(Clone)] +pub struct ShardProofVariable, SC: BabyBearFriConfigVariable> { + pub commitment: ShardCommitment, + pub opened_values: ShardOpenedValues>, + pub opening_proof: TwoAdicPcsProofVariable, + pub chip_ordering: HashMap, + pub public_values: Vec>, +} + +pub const EMPTY: usize = 0x_1111_1111; + +#[derive(Debug, Clone, Copy)] +pub struct StarkVerifier { + _phantom: std::marker::PhantomData<(C, SC, A)>, +} + +pub struct VerifyingKeyHint<'a, SC: StarkGenericConfig, A> { + pub machine: &'a StarkMachine, + pub vk: &'a StarkVerifyingKey, +} + +impl<'a, SC: StarkGenericConfig, A: MachineAir> VerifyingKeyHint<'a, SC, A> { + pub const fn new(machine: &'a StarkMachine, vk: &'a StarkVerifyingKey) -> Self { + Self { machine, vk } + } +} + +impl StarkVerifier +where + C::F: TwoAdicField, + C: CircuitConfig, + SC: BabyBearFriConfigVariable, + >::ProverData>: Clone, + A: MachineAir>, +{ + pub fn natural_domain_for_degree( + config: &SC, + degree: usize, + ) -> TwoAdicMultiplicativeCoset { + >::natural_domain_for_degree( + config.pcs(), + degree, + ) + } + + pub fn verify_shard( + builder: &mut Builder, + vk: &VerifyingKeyVariable, + machine: &StarkMachine, + challenger: &mut SC::FriChallengerVariable, + proof: &ShardProofVariable, + ) where + A: for<'a> Air>, + { + let chips = machine.shard_chips_ordered(&proof.chip_ordering).collect::>(); + + let ShardProofVariable { + commitment, + opened_values, + opening_proof, + chip_ordering, + public_values, + } = proof; + + let log_degrees = opened_values.chips.iter().map(|val| val.log_degree).collect::>(); + + let log_quotient_degrees = + chips.iter().map(|chip| chip.log_quotient_degree()).collect::>(); + + let trace_domains = log_degrees + .iter() + .map(|log_degree| Self::natural_domain_for_degree(machine.config(), 1 << log_degree)) + .collect::>(); + + let ShardCommitment { main_commit, permutation_commit, quotient_commit } = *commitment; + + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext(builder)).collect::>(); + + challenger.observe(builder, permutation_commit); + + let alpha = challenger.sample_ext(builder); + + challenger.observe(builder, quotient_commit); + + let zeta = challenger.sample_ext(builder); + + let preprocessed_domains_points_and_opens = vk + .chip_information + .iter() + .map(|(name, domain, _)| { + let i = chip_ordering[name]; + let values = opened_values.chips[i].preprocessed.clone(); + TwoAdicPcsMatsVariable:: { + domain: *domain, + points: vec![zeta, domain.next_point_variable(builder, zeta)], + values: vec![values.local, values.next], + } + }) + .collect::>(); + + let main_domains_points_and_opens = trace_domains + .iter() + .zip_eq(opened_values.chips.iter()) + .map(|(domain, values)| TwoAdicPcsMatsVariable:: { + domain: *domain, + points: vec![zeta, domain.next_point_variable(builder, zeta)], + values: vec![values.main.local.clone(), values.main.next.clone()], + }) + .collect::>(); + + let perm_domains_points_and_opens = trace_domains + .iter() + .zip_eq(opened_values.chips.iter()) + .map(|(domain, values)| TwoAdicPcsMatsVariable:: { + domain: *domain, + points: vec![zeta, domain.next_point_variable(builder, zeta)], + values: vec![values.permutation.local.clone(), values.permutation.next.clone()], + }) + .collect::>(); + + let quotient_chunk_domains = trace_domains + .iter() + .zip_eq(log_degrees) + .zip_eq(log_quotient_degrees) + .map(|((domain, log_degree), log_quotient_degree)| { + let quotient_degree = 1 << log_quotient_degree; + let quotient_domain = + domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); + quotient_domain.split_domains(quotient_degree) + }) + .collect::>(); + + let quotient_domains_points_and_opens = proof + .opened_values + .chips + .iter() + .zip_eq(quotient_chunk_domains.iter()) + .flat_map(|(values, qc_domains)| { + values.quotient.iter().zip_eq(qc_domains).map(move |(values, q_domain)| { + TwoAdicPcsMatsVariable:: { + domain: *q_domain, + points: vec![zeta], + values: vec![values.clone()], + } + }) + }) + .collect::>(); + + // Create the pcs rounds. + let prep_commit = vk.commitment; + let prep_round = TwoAdicPcsRoundVariable { + batch_commit: prep_commit, + domains_points_and_opens: preprocessed_domains_points_and_opens, + }; + let main_round = TwoAdicPcsRoundVariable { + batch_commit: main_commit, + domains_points_and_opens: main_domains_points_and_opens, + }; + let perm_round = TwoAdicPcsRoundVariable { + batch_commit: permutation_commit, + domains_points_and_opens: perm_domains_points_and_opens, + }; + let quotient_round = TwoAdicPcsRoundVariable { + batch_commit: quotient_commit, + domains_points_and_opens: quotient_domains_points_and_opens, + }; + let rounds = vec![prep_round, main_round, perm_round, quotient_round]; + + // Verify the pcs proof + builder.cycle_tracker_v2_enter("stage-d-verify-pcs".to_string()); + let config = machine.config().fri_config(); + verify_two_adic_pcs::(builder, config, opening_proof, challenger, rounds); + builder.cycle_tracker_v2_exit(); + + // Verify the constrtaint evaluations. + builder.cycle_tracker_v2_enter("stage-e-verify-constraints".to_string()); + for (chip, trace_domain, qc_domains, values) in + izip!(chips.iter(), trace_domains, quotient_chunk_domains, opened_values.chips.iter(),) + { + // Verify the shape of the opening arguments matches the expected values. + Self::verify_opening_shape(chip, values).unwrap(); + // Verify the constraint evaluation. + Self::verify_constraints( + builder, + chip, + values, + trace_domain, + qc_domains, + zeta, + alpha, + &permutation_challenges, + public_values, + ); + } + builder.cycle_tracker_v2_exit(); + } +} + +impl, SC: BabyBearFriConfigVariable> ShardProofVariable { + pub fn contains_cpu(&self) -> bool { + self.chip_ordering.contains_key("CPU") + } + + pub fn contains_memory_init(&self) -> bool { + self.chip_ordering.contains_key("MemoryInit") + } + + pub fn contains_memory_finalize(&self) -> bool { + self.chip_ordering.contains_key("MemoryFinalize") + } +} + +#[allow(unused_imports)] +#[cfg(any(test, feature = "export-tests"))] +pub mod tests { + use std::collections::VecDeque; + + use crate::{ + challenger::{CanCopyChallenger, CanObserveVariable, DuplexChallengerVariable}, + utils::tests::run_test_recursion_with_prover, + BabyBearFriConfig, + }; + + use sp1_core_executor::{programs::tests::FIBONACCI_ELF, Program}; + use sp1_core_machine::{ + io::SP1Stdin, + riscv::RiscvAir, + utils::{prove, setup_logger}, + }; + use sp1_recursion_compiler::{ + config::{InnerConfig, OuterConfig}, + ir::{Builder, DslIr, TracedVec}, + }; + + use sp1_recursion_core_v2::{ + air::Block, machine::RecursionAir, stark::config::BabyBearPoseidon2Outer, + }; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, InnerVal, MachineProver, SP1CoreOpts, + ShardProof, + }; + + use super::*; + use crate::witness::*; + + type F = InnerVal; + type A = RiscvAir; + + pub fn build_verify_shard_with_provers< + C: CircuitConfig>, + SC: BabyBearFriConfigVariable + Default + Sync + Send, + CoreP: MachineProver, + RecP: MachineProver>, + >( + config: SC, + elf: &[u8], + opts: SP1CoreOpts, + num_shards_in_batch: Option, + ) -> (TracedVec>, Vec>) + where + SC::Challenger: Send, + <::ValMmcs as Mmcs>::ProverData< + RowMajorMatrix, + >: Send + Sync, + <::ValMmcs as Mmcs>::Commitment: Send + Sync, + <::ValMmcs as Mmcs>::Proof: Send, + StarkVerifyingKey: Witnessable>, + ShardProof: Witnessable>, + { + // Generate a dummy proof. + setup_logger(); + + let machine = RiscvAir::::machine(SC::default()); + let (_, vk) = machine.setup(&Program::from(elf).unwrap()); + let (proof, _, _) = + prove::<_, CoreP>(Program::from(elf).unwrap(), &SP1Stdin::new(), SC::default(), opts) + .unwrap(); + let mut challenger = machine.config().challenger(); + machine.verify(&vk, &proof, &mut challenger).unwrap(); + println!("Proof generated successfully"); + + // Observe all the commitments. + let mut builder = Builder::::default(); + + let mut witness_stream = Vec::>::new(); + + // Add a hash invocation, since the poseidon2 table expects that it's in the first row. + let mut challenger = config.challenger_variable(&mut builder); + // let vk = VerifyingKeyVariable::from_constant_key_babybear(&mut builder, &vk); + vk.write(&mut witness_stream); + let vk: VerifyingKeyVariable<_, _> = vk.read(&mut builder); + vk.observe_into(&mut builder, &mut challenger); + + let proofs = proof + .shard_proofs + .into_iter() + .map(|proof| { + proof.write(&mut witness_stream); + proof.read(&mut builder) + }) + .collect::>(); + // Observe all the commitments, and put the proofs into the witness stream. + for proof in proofs.iter() { + let ShardCommitment { main_commit, .. } = proof.commitment; + challenger.observe(&mut builder, main_commit); + let pv_slice = &proof.public_values[..machine.num_pv_elts()]; + challenger.observe_slice(&mut builder, pv_slice.iter().cloned()); + } + // Verify the first proof. + let num_shards = num_shards_in_batch.unwrap_or(proofs.len()); + for proof in proofs.into_iter().take(num_shards) { + let mut challenger = challenger.copy(&mut builder); + StarkVerifier::verify_shard(&mut builder, &vk, &machine, &mut challenger, &proof); + } + (builder.operations, witness_stream) + } + + #[test] + fn test_verify_shard_inner() { + let (operations, stream) = + build_verify_shard_with_provers::< + InnerConfig, + BabyBearPoseidon2, + CpuProver<_, _>, + CpuProver<_, _>, + >(BabyBearPoseidon2::new(), FIBONACCI_ELF, SP1CoreOpts::default(), Some(2)); + run_test_recursion_with_prover::>(operations, stream); + } +} diff --git a/crates/recursion/circuit-v2/src/types.rs b/crates/recursion/circuit-v2/src/types.rs new file mode 100644 index 0000000000..33166668fd --- /dev/null +++ b/crates/recursion/circuit-v2/src/types.rs @@ -0,0 +1,111 @@ +use hashbrown::HashMap; +use p3_commit::TwoAdicMultiplicativeCoset; +use p3_field::{AbstractField, TwoAdicField}; +use p3_matrix::Dimensions; + +use sp1_recursion_compiler::ir::{Builder, Ext, Felt}; + +use sp1_recursion_core_v2::DIGEST_SIZE; + +use crate::{ + challenger::CanObserveVariable, hash::FieldHasherVariable, BabyBearFriConfigVariable, + CircuitConfig, +}; + +/// Reference: [sp1_core::stark::StarkVerifyingKey] +#[derive(Clone)] +pub struct VerifyingKeyVariable, SC: BabyBearFriConfigVariable> { + pub commitment: SC::Digest, + pub pc_start: Felt, + pub chip_information: Vec<(String, TwoAdicMultiplicativeCoset, Dimensions)>, + pub chip_ordering: HashMap, +} + +#[derive(Clone)] +pub struct FriProofVariable> { + pub commit_phase_commits: Vec, + pub query_proofs: Vec>, + pub final_poly: Ext, + pub pow_witness: Felt, +} + +/// Reference: https://github.com/Plonky3/Plonky3/blob/4809fa7bedd9ba8f6f5d3267b1592618e3776c57/fri/src/proof.rs#L32 +#[derive(Clone)] +pub struct FriCommitPhaseProofStepVariable> { + pub sibling_value: Ext, + pub opening_proof: Vec, +} + +/// Reference: https://github.com/Plonky3/Plonky3/blob/4809fa7bedd9ba8f6f5d3267b1592618e3776c57/fri/src/proof.rs#L23 +#[derive(Clone)] +pub struct FriQueryProofVariable> { + pub commit_phase_openings: Vec>, +} + +/// Reference: https://github.com/Plonky3/Plonky3/blob/4809fa7bedd9ba8f6f5d3267b1592618e3776c57/fri/src/verifier.rs#L22 +#[derive(Clone)] +pub struct FriChallenges { + pub query_indices: Vec>, + pub betas: Vec>, +} + +#[derive(Clone)] +pub struct TwoAdicPcsProofVariable> { + pub fri_proof: FriProofVariable, + pub query_openings: Vec>>, +} + +#[derive(Clone)] +pub struct BatchOpeningVariable> { + pub opened_values: Vec>>>, + pub opening_proof: Vec, +} + +#[derive(Clone)] +pub struct TwoAdicPcsRoundVariable> { + pub batch_commit: H::Digest, + pub domains_points_and_opens: Vec>, +} + +#[derive(Clone)] +pub struct TwoAdicPcsMatsVariable { + pub domain: TwoAdicMultiplicativeCoset, + pub points: Vec>, + pub values: Vec>>, +} + +impl, SC: BabyBearFriConfigVariable> VerifyingKeyVariable { + pub fn observe_into(&self, builder: &mut Builder, challenger: &mut Challenger) + where + Challenger: CanObserveVariable> + CanObserveVariable, + { + // Observe the commitment. + challenger.observe(builder, self.commitment); + // Observe the pc_start. + challenger.observe(builder, self.pc_start); + } + + /// Hash the verifying key + prep domains into a single digest. + /// poseidon2( commit[0..8] || pc_start || prep_domains[N].{log_n, .size, .shift, .g}) + pub fn hash(&self, builder: &mut Builder) -> SC::Digest + where + C::F: TwoAdicField, + SC::Digest: IntoIterator>, + { + let prep_domains = self.chip_information.iter().map(|(_, domain, _)| domain); + let num_inputs = DIGEST_SIZE + 1 + (4 * prep_domains.len()); + let mut inputs = Vec::with_capacity(num_inputs); + inputs.extend(self.commitment); + inputs.push(self.pc_start); + for domain in prep_domains { + inputs.push(builder.eval(C::F::from_canonical_usize(domain.log_n))); + let size = 1 << domain.log_n; + inputs.push(builder.eval(C::F::from_canonical_usize(size))); + let g = C::F::two_adic_generator(domain.log_n); + inputs.push(builder.eval(domain.shift)); + inputs.push(builder.eval(g)); + } + + SC::hash(builder, &inputs) + } +} diff --git a/crates/recursion/circuit-v2/src/utils.rs b/crates/recursion/circuit-v2/src/utils.rs new file mode 100644 index 0000000000..71a630f2f7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/utils.rs @@ -0,0 +1,181 @@ +use std::borrow::BorrowMut; + +use p3_baby_bear::BabyBear; +use p3_bn254_fr::Bn254Fr; +use p3_field::AbstractField; +use p3_field::PrimeField32; + +use sp1_recursion_compiler::{ + circuit::CircuitV2Builder, + ir::{Builder, Config, Felt, Var}, +}; +use sp1_recursion_core_v2::{ + air::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH, RECURSIVE_PROOF_NUM_PV_ELTS}, + DIGEST_SIZE, +}; +use sp1_stark::Word; + +/// Register and commits the recursion public values. +pub fn commit_recursion_public_values( + builder: &mut Builder, + public_values: &RecursionPublicValues>, +) { + let mut pv_elements: [Felt<_>; RECURSIVE_PROOF_NUM_PV_ELTS] = + core::array::from_fn(|_| builder.uninit()); + *pv_elements.as_mut_slice().borrow_mut() = *public_values; + let pv_elms_no_digest = &pv_elements[0..NUM_PV_ELMS_TO_HASH]; + + for value in pv_elms_no_digest.iter() { + builder.register_public_value(*value); + } + + // Hash the public values. + let pv_digest = builder.poseidon2_hash_v2(&pv_elements[0..NUM_PV_ELMS_TO_HASH]); + for element in pv_digest { + builder.commit_public_value(element); + } +} + +/// Convert 8 BabyBear words into a Bn254Fr field element by shifting by 31 bits each time. The last +/// word becomes the least significant bits. +#[allow(dead_code)] +pub fn babybears_to_bn254(digest: &[BabyBear; 8]) -> Bn254Fr { + let mut result = Bn254Fr::zero(); + for word in digest.iter() { + // Since BabyBear prime is less than 2^31, we can shift by 31 bits each time and still be + // within the Bn254Fr field, so we don't have to truncate the top 3 bits. + result *= Bn254Fr::from_canonical_u64(1 << 31); + result += Bn254Fr::from_canonical_u32(word.as_canonical_u32()); + } + result +} + +/// Convert 32 BabyBear bytes into a Bn254Fr field element. The first byte's most significant 3 bits +/// (which would become the 3 most significant bits) are truncated. +#[allow(dead_code)] +pub fn babybear_bytes_to_bn254(bytes: &[BabyBear; 32]) -> Bn254Fr { + let mut result = Bn254Fr::zero(); + for (i, byte) in bytes.iter().enumerate() { + debug_assert!(byte < &BabyBear::from_canonical_u32(256)); + if i == 0 { + // 32 bytes is more than Bn254 prime, so we need to truncate the top 3 bits. + result = Bn254Fr::from_canonical_u32(byte.as_canonical_u32() & 0x1f); + } else { + result *= Bn254Fr::from_canonical_u32(256); + result += Bn254Fr::from_canonical_u32(byte.as_canonical_u32()); + } + } + result +} + +pub fn felts_to_bn254_var( + builder: &mut Builder, + digest: &[Felt; DIGEST_SIZE], +) -> Var { + let var_2_31: Var<_> = builder.constant(C::N::from_canonical_u32(1 << 31)); + let result = builder.constant(C::N::zero()); + for (i, word) in digest.iter().enumerate() { + let word_bits = builder.num2bits_f_circuit(*word); + let word_var = builder.bits2num_v_circuit(&word_bits); + if i == 0 { + builder.assign(result, word_var); + } else { + builder.assign(result, result * var_2_31 + word_var); + } + } + result +} + +pub fn felt_bytes_to_bn254_var( + builder: &mut Builder, + bytes: &[Felt; 32], +) -> Var { + let var_256: Var<_> = builder.constant(C::N::from_canonical_u32(256)); + let zero_var: Var<_> = builder.constant(C::N::zero()); + let result = builder.constant(C::N::zero()); + for (i, byte) in bytes.iter().enumerate() { + let byte_bits = builder.num2bits_f_circuit(*byte); + if i == 0 { + // Since 32 bytes doesn't fit into Bn254, we need to truncate the top 3 bits. + // For first byte, zero out 3 most significant bits. + for i in 0..3 { + builder.assign(byte_bits[8 - i - 1], zero_var); + } + let byte_var = builder.bits2num_v_circuit(&byte_bits); + builder.assign(result, byte_var); + } else { + let byte_var = builder.bits2num_v_circuit(&byte_bits); + builder.assign(result, result * var_256 + byte_var); + } + } + result +} + +pub fn words_to_bytes(words: &[Word]) -> Vec { + words.iter().flat_map(|w| w.0).collect::>() +} + +#[cfg(any(test, feature = "export-tests"))] +pub(crate) mod tests { + use std::sync::Arc; + + use sp1_core_machine::utils::{run_test_machine_with_prover, setup_logger}; + use sp1_recursion_compiler::{asm::AsmConfig, circuit::AsmCompiler, ir::DslIr}; + + use sp1_recursion_compiler::ir::TracedVec; + use sp1_recursion_core_v2::{machine::RecursionAir, Runtime}; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, InnerChallenge, InnerVal, MachineProver, + }; + + use crate::witness::WitnessBlock; + + type SC = BabyBearPoseidon2; + type F = InnerVal; + type EF = InnerChallenge; + + /// A simplified version of some code from `recursion/core/src/stark/mod.rs`. + /// Takes in a program and runs it with the given witness and generates a proof with a variety + /// of machines depending on the provided test_config. + pub(crate) fn run_test_recursion_with_prover>>( + operations: TracedVec>>, + witness_stream: impl IntoIterator>>, + ) { + setup_logger(); + + let compile_span = tracing::debug_span!("compile").entered(); + let mut compiler = AsmCompiler::>::default(); + let program = Arc::new(compiler.compile(operations)); + compile_span.exit(); + + let config = SC::default(); + + let run_span = tracing::debug_span!("run the recursive program").entered(); + let mut runtime = Runtime::::new(program.clone(), config.perm.clone()); + runtime.witness_stream.extend(witness_stream); + tracing::debug_span!("run").in_scope(|| runtime.run().unwrap()); + assert!(runtime.witness_stream.is_empty()); + run_span.exit(); + + let records = vec![runtime.record]; + + // Run with the poseidon2 wide chip. + let proof_wide_span = tracing::debug_span!("Run test with wide machine").entered(); + let wide_machine = RecursionAir::<_, 3, 0>::machine_wide(SC::default()); + let (pk, vk) = wide_machine.setup(&program); + let result = run_test_machine_with_prover::<_, _, P>(records.clone(), wide_machine, pk, vk); + proof_wide_span.exit(); + + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + } + + #[allow(dead_code)] + pub(crate) fn run_test_recursion( + operations: TracedVec>>, + witness_stream: impl IntoIterator>>, + ) { + run_test_recursion_with_prover::>(operations, witness_stream) + } +} diff --git a/crates/recursion/circuit-v2/src/witness/mod.rs b/crates/recursion/circuit-v2/src/witness/mod.rs new file mode 100644 index 0000000000..c8c90e7c20 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/mod.rs @@ -0,0 +1,212 @@ +mod outer; +mod stark; + +use sp1_recursion_compiler::ir::{Builder, Ext, Felt}; + +pub use outer::*; +use sp1_stark::{ + ChipOpenedValues, Com, InnerChallenge, InnerVal, OpeningProof, ShardCommitment, + ShardOpenedValues, ShardProof, +}; +pub use stark::*; + +use crate::{ + hash::FieldHasherVariable, stark::ShardProofVariable, BabyBearFriConfigVariable, CircuitConfig, + TwoAdicPcsProofVariable, +}; + +pub trait WitnessWriter: Sized { + fn write_bit(&mut self, value: bool); + + fn write_var(&mut self, value: C::N); + + fn write_felt(&mut self, value: C::F); + + fn write_ext(&mut self, value: C::EF); +} + +/// TODO change the name. For now, the name is unique to prevent confusion. +pub trait Witnessable { + type WitnessVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable; + + fn write(&self, witness: &mut impl WitnessWriter); +} + +impl Witnessable for bool { + type WitnessVariable = C::Bit; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_bit(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_bit(*self); + } +} + +impl<'a, C: CircuitConfig, T: Witnessable> Witnessable for &'a T { + type WitnessVariable = T::WitnessVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + (*self).read(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + (*self).write(witness) + } +} + +impl> Witnessable for InnerVal { + type WitnessVariable = Felt; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_felt(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_felt(*self); + } +} + +impl> Witnessable for InnerChallenge { + type WitnessVariable = Ext; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_ext(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + // vec![Block::from(self.as_base_slice())] + witness.write_ext(*self); + } +} + +impl, const N: usize> Witnessable for [T; N] { + type WitnessVariable = [T::WitnessVariable; N]; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + self.iter().map(|x| x.read(builder)).collect::>().try_into().unwrap_or_else( + |x: Vec<_>| { + // Cannot just `.unwrap()` without requiring Debug bounds. + panic!("could not coerce vec of len {} into array of len {N}", x.len()) + }, + ) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + for x in self.iter() { + x.write(witness); + } + } +} + +impl> Witnessable for Vec { + type WitnessVariable = Vec; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + self.iter().map(|x| x.read(builder)).collect() + } + + fn write(&self, witness: &mut impl WitnessWriter) { + for x in self.iter() { + x.write(witness); + } + } +} + +impl, SC: BabyBearFriConfigVariable> + Witnessable for ShardProof +where + Com: Witnessable>::Digest>, + OpeningProof: Witnessable>, +{ + type WitnessVariable = ShardProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commitment = self.commitment.read(builder); + let opened_values = self.opened_values.read(builder); + let opening_proof = self.opening_proof.read(builder); + let public_values = self.public_values.read(builder); + let chip_ordering = self.chip_ordering.clone(); + + ShardProofVariable { + commitment, + opened_values, + opening_proof, + public_values, + chip_ordering, + } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commitment.write(witness); + self.opened_values.write(witness); + self.opening_proof.write(witness); + self.public_values.write(witness); + } +} + +impl> Witnessable for ShardCommitment { + type WitnessVariable = ShardCommitment; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let main_commit = self.main_commit.read(builder); + let permutation_commit = self.permutation_commit.read(builder); + let quotient_commit = self.quotient_commit.read(builder); + Self::WitnessVariable { main_commit, permutation_commit, quotient_commit } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.main_commit.write(witness); + self.permutation_commit.write(witness); + self.quotient_commit.write(witness); + } +} + +impl> Witnessable + for ShardOpenedValues +{ + type WitnessVariable = ShardOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let chips = self.chips.read(builder); + Self::WitnessVariable { chips } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.chips.write(witness); + } +} + +impl> Witnessable + for ChipOpenedValues +{ + type WitnessVariable = ChipOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let preprocessed = self.preprocessed.read(builder); + let main = self.main.read(builder); + let permutation = self.permutation.read(builder); + let quotient = self.quotient.read(builder); + let cumulative_sum = self.cumulative_sum.read(builder); + let log_degree = self.log_degree; + Self::WitnessVariable { + preprocessed, + main, + permutation, + quotient, + cumulative_sum, + log_degree, + } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.preprocessed.write(witness); + self.main.write(witness); + self.permutation.write(witness); + self.quotient.write(witness); + self.cumulative_sum.write(witness); + } +} diff --git a/crates/recursion/circuit-v2/src/witness/outer.rs b/crates/recursion/circuit-v2/src/witness/outer.rs new file mode 100644 index 0000000000..a8fe1b84f7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/outer.rs @@ -0,0 +1,143 @@ +use std::borrow::Borrow; + +use p3_bn254_fr::Bn254Fr; +use p3_field::AbstractField; + +use p3_fri::{CommitPhaseProofStep, QueryProof}; +pub use sp1_recursion_compiler::ir::Witness as OuterWitness; +use sp1_recursion_compiler::{ + config::OuterConfig, + ir::{Builder, Var}, +}; +use sp1_recursion_core_v2::stark::config::{ + BabyBearPoseidon2Outer, OuterBatchOpening, OuterChallenge, OuterChallengeMmcs, OuterDigest, + OuterFriProof, OuterPcsProof, OuterVal, +}; + +use crate::{ + BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, + TwoAdicPcsProofVariable, +}; + +use super::{WitnessWriter, Witnessable}; + +impl WitnessWriter for OuterWitness { + fn write_bit(&mut self, value: bool) { + self.vars.push(Bn254Fr::from_bool(value)); + } + + fn write_var(&mut self, value: Bn254Fr) { + self.vars.push(value); + } + + fn write_felt(&mut self, value: OuterVal) { + self.felts.push(value); + } + + fn write_ext(&mut self, value: OuterChallenge) { + self.exts.push(value); + } +} + +impl Witnessable for Bn254Fr { + type WitnessVariable = Var; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + builder.witness_var() + } + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_var(*self) + } +} + +impl Witnessable for OuterBatchOpening { + type WitnessVariable = BatchOpeningVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let opened_values = self + .opened_values + .read(builder) + .into_iter() + .map(|a| a.into_iter().map(|b| vec![b]).collect()) + .collect(); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { opened_values, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.opened_values.write(witness); + self.opening_proof.write(witness); + } +} + +impl Witnessable for OuterPcsProof { + type WitnessVariable = TwoAdicPcsProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let fri_proof = self.fri_proof.read(builder); + let query_openings = self.query_openings.read(builder); + Self::WitnessVariable { fri_proof, query_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.fri_proof.write(witness); + self.query_openings.write(witness); + } +} + +impl Witnessable for OuterFriProof { + type WitnessVariable = FriProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_commits = self + .commit_phase_commits + .iter() + .map(|commit| { + let commit: &OuterDigest = commit.borrow(); + commit.read(builder) + }) + .collect(); + let query_proofs = self.query_proofs.read(builder); + let final_poly = self.final_poly.read(builder); + let pow_witness = self.pow_witness.read(builder); + Self::WitnessVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_commits.iter().for_each(|commit| { + let commit = Borrow::::borrow(commit); + commit.write(witness); + }); + self.query_proofs.write(witness); + self.final_poly.write(witness); + self.pow_witness.write(witness); + } +} + +impl Witnessable for CommitPhaseProofStep { + type WitnessVariable = FriCommitPhaseProofStepVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let sibling_value = self.sibling_value.read(builder); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { sibling_value, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.sibling_value.write(witness); + self.opening_proof.write(witness); + } +} + +impl Witnessable for QueryProof { + type WitnessVariable = FriQueryProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_openings = self.commit_phase_openings.read(builder); + Self::WitnessVariable { commit_phase_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_openings.write(witness); + } +} diff --git a/crates/recursion/circuit-v2/src/witness/stark.rs b/crates/recursion/circuit-v2/src/witness/stark.rs new file mode 100644 index 0000000000..0f2308c0e7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/stark.rs @@ -0,0 +1,161 @@ +use std::borrow::Borrow; + +use p3_baby_bear::BabyBear; +use p3_field::{AbstractExtensionField, AbstractField}; +use p3_fri::{CommitPhaseProofStep, QueryProof}; + +use sp1_recursion_compiler::ir::{Builder, Config, Ext, Felt}; +use sp1_recursion_core_v2::air::Block; +use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, AirOpenedValues, InnerBatchOpening, InnerChallenge, + InnerChallengeMmcs, InnerDigest, InnerFriProof, InnerPcsProof, InnerVal, +}; + +use crate::{ + BatchOpeningVariable, CircuitConfig, FriCommitPhaseProofStepVariable, FriProofVariable, + FriQueryProofVariable, TwoAdicPcsProofVariable, +}; + +use super::{WitnessWriter, Witnessable}; + +pub type WitnessBlock = Block<::F>; + +impl>> WitnessWriter + for Vec> +{ + fn write_bit(&mut self, value: bool) { + self.push(Block::from(C::F::from_bool(value))) + } + + fn write_var(&mut self, _value: ::N) { + unimplemented!("Cannot write Var in this configuration") + } + + fn write_felt(&mut self, value: ::F) { + self.push(Block::from(value)) + } + + fn write_ext(&mut self, value: ::EF) { + self.push(Block::from(value.as_base_slice())) + } +} + +impl> Witnessable + for AirOpenedValues +{ + type WitnessVariable = AirOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let local = self.local.read(builder); + let next = self.next.read(builder); + Self::WitnessVariable { local, next } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.local.write(witness); + self.next.write(witness); + } +} + +impl>> Witnessable + for InnerPcsProof +{ + type WitnessVariable = TwoAdicPcsProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let fri_proof = self.fri_proof.read(builder); + let query_openings = self.query_openings.read(builder); + Self::WitnessVariable { fri_proof, query_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.fri_proof.write(witness); + self.query_openings.write(witness); + } +} + +impl Witnessable for InnerBatchOpening +where + C: CircuitConfig>, +{ + type WitnessVariable = BatchOpeningVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let opened_values = self + .opened_values + .read(builder) + .into_iter() + .map(|a| a.into_iter().map(|b| vec![b]).collect()) + .collect(); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { opened_values, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.opened_values.write(witness); + self.opening_proof.write(witness); + } +} + +impl>> Witnessable + for InnerFriProof +{ + type WitnessVariable = FriProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_commits = self + .commit_phase_commits + .iter() + .map(|commit| { + let commit: &InnerDigest = commit.borrow(); + commit.read(builder) + }) + .collect(); + let query_proofs = self.query_proofs.read(builder); + let final_poly = self.final_poly.read(builder); + let pow_witness = self.pow_witness.read(builder); + Self::WitnessVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_commits.iter().for_each(|commit| { + let commit = Borrow::::borrow(commit); + commit.write(witness); + }); + self.query_proofs.write(witness); + self.final_poly.write(witness); + self.pow_witness.write(witness); + } +} + +impl>> Witnessable + for QueryProof +{ + type WitnessVariable = FriQueryProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_openings = self.commit_phase_openings.read(builder); + Self::WitnessVariable { commit_phase_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_openings.write(witness); + } +} + +impl>> Witnessable + for CommitPhaseProofStep +{ + type WitnessVariable = FriCommitPhaseProofStepVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let sibling_value = self.sibling_value.read(builder); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { sibling_value, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.sibling_value.write(witness); + self.opening_proof.write(witness); + } +} diff --git a/recursion/circuit/CHANGELOG.md b/crates/recursion/circuit/CHANGELOG.md similarity index 100% rename from recursion/circuit/CHANGELOG.md rename to crates/recursion/circuit/CHANGELOG.md diff --git a/recursion/circuit/Cargo.toml b/crates/recursion/circuit/Cargo.toml similarity index 92% rename from recursion/circuit/Cargo.toml rename to crates/recursion/circuit/Cargo.toml index 7fac1a71d4..9bcf439798 100644 --- a/recursion/circuit/Cargo.toml +++ b/crates/recursion/circuit/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-circuit" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -17,7 +17,8 @@ p3-fri = { workspace = true } p3-matrix = { workspace = true } p3-util = { workspace = true } sp1-recursion-core = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } +sp1-stark = { workspace = true } itertools = "0.13.0" serde = { version = "1.0.204", features = ["derive"] } sp1-recursion-derive = { workspace = true } diff --git a/recursion/circuit/build/verifier.go b/crates/recursion/circuit/build/verifier.go similarity index 100% rename from recursion/circuit/build/verifier.go rename to crates/recursion/circuit/build/verifier.go diff --git a/recursion/circuit/src/challenger.rs b/crates/recursion/circuit/src/challenger.rs similarity index 90% rename from recursion/circuit/src/challenger.rs rename to crates/recursion/circuit/src/challenger.rs index aa947f6b04..13602835a7 100644 --- a/recursion/circuit/src/challenger.rs +++ b/crates/recursion/circuit/src/challenger.rs @@ -1,12 +1,7 @@ -use p3_field::AbstractField; -use p3_field::Field; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Ext; -use sp1_recursion_compiler::ir::{Builder, Config, Felt, Var}; +use p3_field::{AbstractField, Field}; +use sp1_recursion_compiler::ir::{Array, Builder, Config, Ext, Felt, Var}; -use crate::poseidon2::Poseidon2CircuitBuilder; -use crate::DIGEST_SIZE; -use crate::SPONGE_SIZE; +use crate::{poseidon2::Poseidon2CircuitBuilder, DIGEST_SIZE, SPONGE_SIZE}; #[derive(Clone)] pub struct MultiField32ChallengerVariable { @@ -92,9 +87,7 @@ impl MultiField32ChallengerVariable { self.duplexing(builder); } - self.output_buffer - .pop() - .expect("output buffer should be non-empty") + self.output_buffer.pop().expect("output buffer should be non-empty") } pub fn sample_ext(&mut self, builder: &mut Builder) -> Ext { @@ -122,8 +115,7 @@ pub fn reduce_32(builder: &mut Builder, vals: &[Felt]) -> Va let mut power = C::N::one(); let result: Var = builder.eval(C::N::zero()); for val in vals.iter() { - let bits = builder.num2bits_f_circuit(*val); - let val = builder.bits2num_v_circuit(&bits); + let val = builder.felt2var_circuit(*val); builder.assign(result, result + val * power); power *= C::N::from_canonical_u64(1u64 << 32); } @@ -150,24 +142,22 @@ pub fn split_32(builder: &mut Builder, val: Var, n: usize) - mod tests { use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; - use p3_challenger::FieldChallenger; - use p3_challenger::{CanObserve, CanSample}; - use p3_field::extension::BinomialExtensionField; - use p3_field::reduce_32 as reduce_32_gt; - use p3_field::split_32 as split_32_gt; - use p3_field::AbstractField; + use p3_challenger::{CanObserve, CanSample, FieldChallenger}; + use p3_field::{ + extension::BinomialExtensionField, reduce_32 as reduce_32_gt, split_32 as split_32_gt, + AbstractField, + }; use p3_symmetric::Hash; - use sp1_recursion_compiler::config::OuterConfig; - use sp1_recursion_compiler::constraints::ConstraintCompiler; - use sp1_recursion_compiler::ir::SymbolicExt; - use sp1_recursion_compiler::ir::{Builder, Witness}; + use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::ConstraintCompiler, + ir::{Builder, SymbolicExt, Witness}, + }; use sp1_recursion_core::stark::config::{outer_perm, OuterChallenger}; use sp1_recursion_gnark_ffi::PlonkBn254Prover; - use super::reduce_32; - use super::split_32; - use crate::challenger::MultiField32ChallengerVariable; - use crate::DIGEST_SIZE; + use super::{reduce_32, split_32}; + use crate::{challenger::MultiField32ChallengerVariable, DIGEST_SIZE}; #[test] fn test_num2bits_v() { diff --git a/recursion/circuit/src/constraints.rs b/crates/recursion/circuit/src/constraints.rs similarity index 78% rename from recursion/circuit/src/constraints.rs rename to crates/recursion/circuit/src/constraints.rs index 255af078da..f2df585d09 100644 --- a/recursion/circuit/src/constraints.rs +++ b/crates/recursion/circuit/src/constraints.rs @@ -1,25 +1,22 @@ use p3_air::Air; use p3_commit::LagrangeSelectors; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use p3_field::TwoAdicField; -use sp1_core::air::MachineAir; -use sp1_core::stark::AirOpenedValues; -use sp1_core::stark::PROOF_MAX_NUM_PVS; -use sp1_core::stark::{MachineChip, StarkGenericConfig}; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::ExtensionOperand; -use sp1_recursion_compiler::ir::Felt; -use sp1_recursion_compiler::ir::{Builder, Config, Ext}; -use sp1_recursion_compiler::prelude::SymbolicExt; +use p3_field::{AbstractExtensionField, AbstractField, TwoAdicField}; +use sp1_recursion_compiler::{ + ir::{Array, Builder, Config, Ext, ExtensionOperand, Felt, SymbolicFelt}, + prelude::SymbolicExt, +}; use sp1_recursion_program::commit::PolynomialSpaceVariable; use sp1_recursion_program::stark::RecursiveVerifierConstraintFolder; +use sp1_stark::{ + air::MachineAir, AirOpenedValues, MachineChip, StarkGenericConfig, PROOF_MAX_NUM_PVS, +}; -use crate::domain::TwoAdicMultiplicativeCosetVariable; -use crate::stark::StarkVerifierCircuit; -use crate::types::ChipOpenedValuesVariable; -use crate::types::ChipOpening; +use crate::{ + domain::TwoAdicMultiplicativeCosetVariable, + stark::StarkVerifierCircuit, + types::{ChipOpenedValuesVariable, ChipOpening}, +}; impl StarkVerifierCircuit where @@ -92,7 +89,7 @@ where .iter() .enumerate() .map(|(i, domain)| { - qc_domains + let (zs, zinvs) = qc_domains .iter() .enumerate() .filter(|(j, _)| *j != i) @@ -100,12 +97,15 @@ where // Calculate: other_domain.zp_at_point(zeta) // * other_domain.zp_at_point(domain.first_point()).inverse() let first_point = domain.first_point(builder); - let first_point_ext = first_point.to_operand().symbolic(); - let first_point: Ext<_, _> = builder.eval(first_point_ext); - let z = other_domain.zp_at_point(builder, first_point); - other_domain.zp_at_point(builder, zeta) * z.inverse() + let z = other_domain.zp_at_point_f(builder, first_point); + ( + other_domain.zp_at_point(builder, zeta).to_operand().symbolic(), + z.inverse(), + ) }) - .product::>() + .unzip::<_, _, Vec<_>, Vec<_>>(); + zs.into_iter().product::>() + * zinvs.into_iter().product::>() }) .collect::>>() .into_iter() @@ -141,6 +141,8 @@ where ) where A: MachineAir + for<'a> Air>, { + builder.cycle_tracker("verify constraints"); + let opening = ChipOpening::from_variable(builder, chip, opening); let sels = trace_domain.selectors_at_point(builder, zeta); @@ -157,6 +159,8 @@ where let quotient: Ext<_, _> = Self::recompute_quotient(builder, &opening, qc_domains, zeta); builder.assert_ext_eq(folded_constraints * sels.inv_zeroifier, quotient); + + builder.cycle_tracker("verify constraints"); } } @@ -167,13 +171,6 @@ mod tests { use p3_baby_bear::DiffusionMatrixBabyBear; use p3_challenger::{CanObserve, FieldChallenger}; use p3_commit::{Pcs, PolynomialSpace}; - use sp1_core::{ - stark::{ - Chip, Com, CpuProver, Dom, MachineProver, OpeningProof, PcsProverData, ShardCommitment, - ShardProof, StarkGenericConfig, StarkMachine, - }, - utils::SP1CoreOpts, - }; use sp1_recursion_compiler::{ config::OuterConfig, constraints::ConstraintCompiler, @@ -185,6 +182,10 @@ mod tests { stark::{config::BabyBearPoseidon2Outer, RecursionAirWideDeg3}, }; use sp1_recursion_gnark_ffi::PlonkBn254Prover; + use sp1_stark::{ + Chip, Com, CpuProver, Dom, MachineProver, OpeningProof, PcsProverData, SP1CoreOpts, + ShardCommitment, ShardProof, StarkGenericConfig, StarkMachine, + }; use crate::stark::{tests::basic_program, StarkVerifierCircuit}; @@ -208,27 +209,17 @@ mod tests { Com: Send + Sync, PcsProverData: Send + Sync, SC::Val: p3_field::PrimeField32, - ::Val: - p3_field::extension::BinomiallyExtendable<4>, + ::Val: p3_field::extension::BinomiallyExtendable<4>, { - let ShardProof { - commitment, - opened_values, - .. - } = proof; - - let ShardCommitment { - permutation_commit, - quotient_commit, - .. - } = commitment; + let ShardProof { commitment, opened_values, .. } = proof; + + let ShardCommitment { permutation_commit, quotient_commit, .. } = commitment; // Extract verification metadata. let pcs = machine.config().pcs(); - let permutation_challenges = (0..2) - .map(|_| challenger.sample_ext_element::()) - .collect::>(); + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext_element::()).collect::>(); challenger.observe(permutation_commit.clone()); @@ -239,20 +230,12 @@ mod tests { let zeta = challenger.sample_ext_element::(); - let chips = machine - .shard_chips_ordered(&proof.chip_ordering) - .collect::>(); + let chips = machine.shard_chips_ordered(&proof.chip_ordering).collect::>(); - let log_degrees = opened_values - .chips - .iter() - .map(|val| val.log_degree) - .collect::>(); + let log_degrees = opened_values.chips.iter().map(|val| val.log_degree).collect::>(); - let log_quotient_degrees = chips - .iter() - .map(|chip| chip.log_quotient_degree()) - .collect::>(); + let log_quotient_degrees = + chips.iter().map(|chip| chip.log_quotient_degree()).collect::>(); let trace_domains = log_degrees .iter() @@ -271,14 +254,7 @@ mod tests { }) .collect::>(); - ( - chips, - trace_domains, - quotient_chunk_domains, - permutation_challenges, - alpha, - zeta, - ) + (chips, trace_domains, quotient_chunk_domains, permutation_challenges, alpha, zeta) } #[test] @@ -288,7 +264,7 @@ mod tests { type EF = ::Challenge; type A = RecursionAirWideDeg3; - sp1_core::utils::setup_logger(); + sp1_core_machine::utils::setup_logger(); let program = basic_program::(); let config = SC::new(); let mut runtime = Runtime::::new_no_perm(&program); @@ -298,12 +274,7 @@ mod tests { let (pk, vk) = prover.setup(&program); let mut challenger = prover.config().challenger(); let proof = prover - .prove( - &pk, - vec![runtime.record], - &mut challenger, - SP1CoreOpts::recursion(), - ) + .prove(&pk, vec![runtime.record], &mut challenger, SP1CoreOpts::recursion()) .unwrap(); let mut challenger = prover.config().challenger(); @@ -336,11 +307,8 @@ mod tests { let alpha = builder.eval(alpha_val.cons()); let zeta = builder.eval(zeta_val.cons()); let trace_domain = builder.constant(trace_domain_val); - let pv_felts = proof - .public_values - .iter() - .map(|v| builder.constant(*v)) - .collect_vec(); + let pv_felts = + proof.public_values.iter().map(|v| builder.constant(*v)).collect_vec(); let public_values = builder.vec(pv_felts); let qc_domains = qc_domains_vals .iter() diff --git a/recursion/circuit/src/domain.rs b/crates/recursion/circuit/src/domain.rs similarity index 90% rename from recursion/circuit/src/domain.rs rename to crates/recursion/circuit/src/domain.rs index e7b57801e2..52b96536f2 100644 --- a/recursion/circuit/src/domain.rs +++ b/crates/recursion/circuit/src/domain.rs @@ -1,10 +1,7 @@ use p3_commit::{LagrangeSelectors, TwoAdicMultiplicativeCoset}; -use p3_field::AbstractExtensionField; -use p3_field::Field; -use p3_field::{AbstractField, TwoAdicField}; +use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; use sp1_recursion_compiler::prelude::*; -use sp1_recursion_program::commit::PolynomialSpaceVariable; -use sp1_recursion_program::fri::types::FriConfigVariable; +use sp1_recursion_program::{commit::PolynomialSpaceVariable, fri::types::FriConfigVariable}; #[derive(Clone, Copy)] pub struct TwoAdicMultiplicativeCosetVariable { @@ -26,6 +23,15 @@ impl TwoAdicMultiplicativeCosetVariable { pub fn first_point(&self, builder: &mut Builder) -> Felt { builder.eval(self.shift) } + pub fn zp_at_point_f( + &self, + builder: &mut Builder, + point: Felt<::F>, + ) -> Felt<::F> { + let unshifted_power = builder + .exp_power_of_2_v::>(point * self.shift.inverse(), Usize::Const(self.log_n)); + builder.eval(unshifted_power - C::F::one()) + } } impl FromConstant for TwoAdicMultiplicativeCosetVariable diff --git a/recursion/circuit/src/fri.rs b/crates/recursion/circuit/src/fri.rs similarity index 68% rename from recursion/circuit/src/fri.rs rename to crates/recursion/circuit/src/fri.rs index 7e30d656b0..e847d5a3b4 100644 --- a/recursion/circuit/src/fri.rs +++ b/crates/recursion/circuit/src/fri.rs @@ -1,22 +1,29 @@ use itertools::{izip, Itertools}; +use p3_bn254_fr::Bn254Fr; use p3_commit::PolynomialSpace; -use p3_field::AbstractField; -use p3_field::TwoAdicField; -use p3_fri::FriConfig; +use p3_field::{AbstractField, TwoAdicField}; +use p3_fri::{FriConfig, TwoAdicFriPcsProof}; use p3_matrix::Dimensions; use p3_util::log2_strict_usize; -use sp1_recursion_compiler::ir::{Builder, Config, Felt}; -use sp1_recursion_compiler::prelude::*; -use sp1_recursion_core::stark::config::OuterChallengeMmcs; - -use crate::mmcs::verify_batch; -use crate::types::FriChallenges; -use crate::types::FriProofVariable; -use crate::types::FriQueryProofVariable; -use crate::types::OuterDigestVariable; -use crate::types::TwoAdicPcsProofVariable; -use crate::types::TwoAdicPcsRoundVariable; -use crate::{challenger::MultiField32ChallengerVariable, DIGEST_SIZE}; +use sp1_recursion_compiler::{ + config::OuterConfig, + ir::{Builder, Config, Felt}, + prelude::*, +}; +use sp1_recursion_core::stark::config::{ + OuterChallenge, OuterChallengeMmcs, OuterFriProof, OuterVal, OuterValMmcs, +}; + +use crate::{ + challenger::MultiField32ChallengerVariable, + mmcs::verify_batch, + types::{ + BatchOpeningVariable, FriChallenges, FriCommitPhaseProofStepVariable, FriProofVariable, + FriQueryProofVariable, OuterDigestVariable, TwoAdicPcsProofVariable, + TwoAdicPcsRoundVariable, + }, + DIGEST_SIZE, +}; pub fn verify_shape_and_sample_challenges( builder: &mut Builder, @@ -43,14 +50,10 @@ pub fn verify_shape_and_sample_challenges( challenger.check_witness(builder, config.proof_of_work_bits, proof.pow_witness); let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; - let query_indices: Vec> = (0..config.num_queries) - .map(|_| challenger.sample_bits(builder, log_max_height)) - .collect(); + let query_indices: Vec> = + (0..config.num_queries).map(|_| challenger.sample_bits(builder, log_max_height)).collect(); - FriChallenges { - query_indices, - betas, - } + FriChallenges { query_indices, betas } } pub fn verify_two_adic_pcs( @@ -60,6 +63,7 @@ pub fn verify_two_adic_pcs( challenger: &mut MultiField32ChallengerVariable, rounds: Vec>, ) { + builder.cycle_tracker("2adic"); let alpha = challenger.sample_ext(builder); let fri_challenges = @@ -84,10 +88,8 @@ pub fn verify_two_adic_pcs( for (batch_opening, round) in izip!(query_opening.clone(), &rounds) { let batch_commit = round.batch_commit; let mats = &round.mats; - let batch_heights = mats - .iter() - .map(|mat| mat.domain.size() << config.log_blowup) - .collect_vec(); + let batch_heights = + mats.iter().map(|mat| mat.domain.size() << config.log_blowup).collect_vec(); let batch_dims = batch_heights .iter() .map(|&height| Dimensions { width: 0, height }) @@ -126,6 +128,7 @@ pub fn verify_two_adic_pcs( let x: Felt<_> = builder.eval(g * two_adic_generator_exp); for (z, ps_at_z) in izip!(mat_points, mat_values) { + builder.cycle_tracker("2adic-hotloop"); let mut acc: Ext = builder.eval(SymbolicExt::from_f(C::EF::zero())); for (p_at_x, &p_at_z) in izip!(mat_opening.clone(), ps_at_z) { @@ -140,20 +143,18 @@ pub fn verify_two_adic_pcs( log_height_pow[log_height] += 1; } ro[log_height] = builder.eval(ro[log_height] + acc / (*z - x)); + builder.cycle_tracker("2adic-hotloop"); } } } ro }) .collect::>(); + builder.cycle_tracker("2adic"); - verify_challenges( - builder, - config, - &proof.fri_proof, - &fri_challenges, - reduced_openings, - ); + builder.cycle_tracker("challenges"); + verify_challenges(builder, config, &proof.fri_proof, &fri_challenges, reduced_openings); + builder.cycle_tracker("challenges"); } pub fn verify_challenges( @@ -164,11 +165,9 @@ pub fn verify_challenges( reduced_openings: Vec<[Ext; 32]>, ) { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; - for (&index, query_proof, ro) in izip!( - &challenges.query_indices, - &proof.query_proofs, - reduced_openings - ) { + for (&index, query_proof, ro) in + izip!(&challenges.query_indices, &proof.query_proofs, reduced_openings) + { let folded_eval = verify_query( builder, proof.commit_phase_commits.clone(), @@ -193,27 +192,27 @@ pub fn verify_query( log_max_height: usize, ) -> Ext { let mut folded_eval: Ext = builder.eval(SymbolicExt::from_f(C::EF::zero())); - let two_adic_generator = builder.eval(SymbolicExt::from_f(C::EF::two_adic_generator( - log_max_height, - ))); + let two_adic_generator = + builder.eval(SymbolicExt::from_f(C::EF::two_adic_generator(log_max_height))); let index_bits = builder.num2bits_v_circuit(index, 32); let rev_reduced_index = builder.reverse_bits_len_circuit(index_bits.clone(), log_max_height); let mut x = builder.exp_e_bits(two_adic_generator, rev_reduced_index); builder.reduce_e(x); let mut offset = 0; - for (log_folded_height, commit, step, beta) in izip!( - (0..log_max_height).rev(), - commit_phase_commits, - &proof.commit_phase_openings, - betas, - ) { + for (log_folded_height, commit, step, beta) in + izip!((0..log_max_height).rev(), commit_phase_commits, &proof.commit_phase_openings, betas,) + { folded_eval = builder.eval(folded_eval + reduced_openings[log_folded_height + 1]); let one: Var<_> = builder.eval(C::N::one()); let index_sibling: Var<_> = builder.eval(one - index_bits.clone()[offset]); let index_pair = &index_bits[(offset + 1)..]; + // Reduce folded_eval (mod the BabyBear prime) since it gets used multiple times below and + // the reductions will be repeated. + builder.reduce_e(folded_eval); + let evals_ext = [ builder.select_ef(index_sibling, folded_eval, step.sibling_value), builder.select_ef(index_sibling, step.sibling_value, folded_eval), @@ -223,10 +222,7 @@ pub fn verify_query( builder.ext2felt_circuit(evals_ext[1]).to_vec(), ]; - let dims = &[Dimensions { - width: 2, - height: (1 << log_folded_height), - }]; + let dims = &[Dimensions { width: 2, height: (1 << log_folded_height) }]; verify_batch::( builder, commit, @@ -250,7 +246,89 @@ pub fn verify_query( folded_eval } +pub fn const_fri_proof( + builder: &mut Builder, + fri_proof: OuterFriProof, +) -> FriProofVariable { + // Set the commit phase commits. + let commit_phase_commits = fri_proof + .commit_phase_commits + .iter() + .map(|commit| { + let commit: [Bn254Fr; DIGEST_SIZE] = (*commit).into(); + let commit: Var<_> = builder.eval(commit[0]); + [commit; DIGEST_SIZE] + }) + .collect::>(); + + // Set the query proofs. + let query_proofs = fri_proof + .query_proofs + .iter() + .map(|query_proof| { + let commit_phase_openings = query_proof + .commit_phase_openings + .iter() + .map(|commit_phase_opening| { + let sibling_value = + builder.eval(SymbolicExt::from_f(commit_phase_opening.sibling_value)); + let opening_proof = commit_phase_opening + .opening_proof + .iter() + .map(|sibling| { + let commit: Var<_> = builder.eval(sibling[0]); + [commit; DIGEST_SIZE] + }) + .collect::>(); + FriCommitPhaseProofStepVariable { sibling_value, opening_proof } + }) + .collect::>(); + FriQueryProofVariable { commit_phase_openings } + }) + .collect::>(); + + // Initialize the FRI proof variable. + FriProofVariable { + commit_phase_commits, + query_proofs, + final_poly: builder.eval(SymbolicExt::from_f(fri_proof.final_poly)), + pow_witness: builder.eval(fri_proof.pow_witness), + } +} +pub fn const_two_adic_pcs_proof( + builder: &mut Builder, + proof: TwoAdicFriPcsProof, +) -> TwoAdicPcsProofVariable { + let fri_proof = const_fri_proof(builder, proof.fri_proof); + let query_openings = proof + .query_openings + .iter() + .map(|query_opening| { + query_opening + .iter() + .map(|opening| BatchOpeningVariable { + opened_values: opening + .opened_values + .iter() + .map(|opened_value| { + opened_value + .iter() + .map(|value| vec![builder.eval::, _>(*value)]) + .collect::>() + }) + .collect::>(), + opening_proof: opening + .opening_proof + .iter() + .map(|opening_proof| [builder.eval(opening_proof[0])]) + .collect::>(), + }) + .collect::>() + }) + .collect::>(); + TwoAdicPcsProofVariable { fri_proof, query_openings } +} #[cfg(test)] pub mod tests { @@ -258,142 +336,38 @@ pub mod tests { use p3_challenger::{CanObserve, CanSample, FieldChallenger}; use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; use p3_field::AbstractField; - use p3_fri::{verifier, TwoAdicFriPcsProof}; + use p3_fri::verifier; use p3_matrix::dense::RowMajorMatrix; use rand::rngs::OsRng; use sp1_recursion_compiler::{ config::OuterConfig, constraints::ConstraintCompiler, - ir::{Builder, Ext, Felt, SymbolicExt, Var, Witness}, + ir::{Builder, Ext, SymbolicExt, Var, Witness}, }; use sp1_recursion_core::stark::config::{ - outer_perm, test_fri_config, OuterChallenge, OuterChallengeMmcs, OuterChallenger, - OuterCompress, OuterDft, OuterFriProof, OuterHash, OuterPcs, OuterVal, OuterValMmcs, + outer_perm, test_fri_config, OuterChallenge, OuterChallenger, OuterCompress, OuterDft, + OuterHash, OuterPcs, OuterVal, OuterValMmcs, }; use sp1_recursion_gnark_ffi::PlonkBn254Prover; use super::{verify_shape_and_sample_challenges, verify_two_adic_pcs, TwoAdicPcsRoundVariable}; use crate::{ challenger::MultiField32ChallengerVariable, - fri::FriQueryProofVariable, - types::{ - BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, - OuterDigestVariable, TwoAdicPcsMatsVariable, TwoAdicPcsProofVariable, - }, + types::{OuterDigestVariable, TwoAdicPcsMatsVariable}, DIGEST_SIZE, }; - pub fn const_fri_proof( - builder: &mut Builder, - fri_proof: OuterFriProof, - ) -> FriProofVariable { - // Set the commit phase commits. - let commit_phase_commits = fri_proof - .commit_phase_commits - .iter() - .map(|commit| { - let commit: [Bn254Fr; DIGEST_SIZE] = (*commit).into(); - let commit: Var<_> = builder.eval(commit[0]); - [commit; DIGEST_SIZE] - }) - .collect::>(); - - // Set the query proofs. - let query_proofs = fri_proof - .query_proofs - .iter() - .map(|query_proof| { - let commit_phase_openings = query_proof - .commit_phase_openings - .iter() - .map(|commit_phase_opening| { - let sibling_value = - builder.eval(SymbolicExt::from_f(commit_phase_opening.sibling_value)); - let opening_proof = commit_phase_opening - .opening_proof - .iter() - .map(|sibling| { - let commit: Var<_> = builder.eval(sibling[0]); - [commit; DIGEST_SIZE] - }) - .collect::>(); - FriCommitPhaseProofStepVariable { - sibling_value, - opening_proof, - } - }) - .collect::>(); - FriQueryProofVariable { - commit_phase_openings, - } - }) - .collect::>(); - - // Initialize the FRI proof variable. - FriProofVariable { - commit_phase_commits, - query_proofs, - final_poly: builder.eval(SymbolicExt::from_f(fri_proof.final_poly)), - pow_witness: builder.eval(fri_proof.pow_witness), - } - } - - pub fn const_two_adic_pcs_proof( - builder: &mut Builder, - proof: TwoAdicFriPcsProof, - ) -> TwoAdicPcsProofVariable { - let fri_proof = const_fri_proof(builder, proof.fri_proof); - let query_openings = proof - .query_openings - .iter() - .map(|query_opening| { - query_opening - .iter() - .map(|opening| BatchOpeningVariable { - opened_values: opening - .opened_values - .iter() - .map(|opened_value| { - opened_value - .iter() - .map(|value| vec![builder.eval::, _>(*value)]) - .collect::>() - }) - .collect::>(), - opening_proof: opening - .opening_proof - .iter() - .map(|opening_proof| [builder.eval(opening_proof[0])]) - .collect::>(), - }) - .collect::>() - }) - .collect::>(); - TwoAdicPcsProofVariable { - fri_proof, - query_openings, - } - } - pub fn const_two_adic_pcs_rounds( builder: &mut Builder, commit: [Bn254Fr; DIGEST_SIZE], - os: Vec<( - TwoAdicMultiplicativeCoset, - Vec<(OuterChallenge, Vec)>, - )>, - ) -> ( - OuterDigestVariable, - Vec>, - ) { + os: Vec<(TwoAdicMultiplicativeCoset, Vec<(OuterChallenge, Vec)>)>, + ) -> (OuterDigestVariable, Vec>) { let commit: OuterDigestVariable = [builder.eval(commit[0])]; let mut mats = Vec::new(); for (domain, poly) in os.into_iter() { - let points: Vec> = poly - .iter() - .map(|(p, _)| builder.eval(SymbolicExt::from_f(*p))) - .collect::>(); + let points: Vec> = + poly.iter().map(|(p, _)| builder.eval(SymbolicExt::from_f(*p))).collect::>(); let values: Vec>> = poly .iter() .map(|(_, v)| { @@ -403,21 +377,11 @@ pub mod tests { .collect::>() }) .collect::>(); - let mat = TwoAdicPcsMatsVariable { - domain, - points, - values, - }; + let mat = TwoAdicPcsMatsVariable { domain, points, values }; mats.push(mat); } - ( - commit, - vec![TwoAdicPcsRoundVariable { - batch_commit: commit, - mats, - }], - ) + (commit, vec![TwoAdicPcsRoundVariable { batch_commit: commit, mats }]) } #[test] @@ -430,12 +394,8 @@ pub mod tests { let compress = OuterCompress::new(perm.clone()); let val_mmcs = OuterValMmcs::new(hash, compress); let dft = OuterDft {}; - let pcs: OuterPcs = OuterPcs::new( - log_degrees.iter().copied().max().unwrap(), - dft, - val_mmcs, - fri_config, - ); + let pcs: OuterPcs = + OuterPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); // Generate proof. let domains_and_polys = log_degrees @@ -457,10 +417,7 @@ pub mod tests { let mut challenger = OuterChallenger::new(perm.clone()).unwrap(); challenger.observe(commit); let zeta = challenger.sample_ext_element::(); - let points = domains_and_polys - .iter() - .map(|_| vec![zeta]) - .collect::>(); + let points = domains_and_polys.iter().map(|_| vec![zeta]).collect::>(); let (_, proof) = pcs.open(vec![(&data, points)], &mut challenger); // Verify proof. @@ -477,7 +434,7 @@ pub mod tests { // Define circuit. let mut builder = Builder::::default(); let config = test_fri_config(); - let fri_proof = const_fri_proof(&mut builder, proof.fri_proof); + let fri_proof = super::const_fri_proof(&mut builder, proof.fri_proof); let mut challenger = MultiField32ChallengerVariable::new(&mut builder); let commit: [Bn254Fr; DIGEST_SIZE] = commit.into(); @@ -516,12 +473,8 @@ pub mod tests { let compress = OuterCompress::new(perm.clone()); let val_mmcs = OuterValMmcs::new(hash, compress); let dft = OuterDft {}; - let pcs: OuterPcs = OuterPcs::new( - log_degrees.iter().copied().max().unwrap(), - dft, - val_mmcs, - fri_config, - ); + let pcs: OuterPcs = + OuterPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); // Generate proof. let domains_and_polys = log_degrees @@ -543,10 +496,7 @@ pub mod tests { let mut challenger = OuterChallenger::new(perm.clone()).unwrap(); challenger.observe(commit); let zeta = challenger.sample_ext_element::(); - let points = domains_and_polys - .iter() - .map(|_| vec![zeta]) - .collect::>(); + let points = domains_and_polys.iter().map(|_| vec![zeta]).collect::>(); let (opening, proof) = pcs.open(vec![(&data, points)], &mut challenger); // Verify proof. @@ -561,13 +511,12 @@ pub mod tests { .zip(&opening[0]) .map(|((domain, _), mat_openings)| (*domain, vec![(zeta, mat_openings[0].clone())])) .collect(); - pcs.verify(vec![(commit, os.clone())], &proof, &mut challenger) - .unwrap(); + pcs.verify(vec![(commit, os.clone())], &proof, &mut challenger).unwrap(); // Define circuit. let mut builder = Builder::::default(); let config = test_fri_config(); - let proof = const_two_adic_pcs_proof(&mut builder, proof); + let proof = super::const_two_adic_pcs_proof(&mut builder, proof); let (commit, rounds) = const_two_adic_pcs_rounds(&mut builder, commit.into(), os); let mut challenger = MultiField32ChallengerVariable::new(&mut builder); challenger.observe_commitment(&mut builder, commit); diff --git a/recursion/circuit/src/lib.rs b/crates/recursion/circuit/src/lib.rs similarity index 92% rename from recursion/circuit/src/lib.rs rename to crates/recursion/circuit/src/lib.rs index 717e2d4eda..bfc01386a5 100644 --- a/recursion/circuit/src/lib.rs +++ b/crates/recursion/circuit/src/lib.rs @@ -24,12 +24,11 @@ mod tests { use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; use p3_field::AbstractField; - use sp1_recursion_compiler::config::OuterConfig; - use sp1_recursion_compiler::constraints::ConstraintCompiler; - use sp1_recursion_compiler::ir::Config; - use sp1_recursion_compiler::ir::Ext; - use sp1_recursion_compiler::ir::ExtConst; - use sp1_recursion_compiler::ir::{Builder, Felt, Witness}; + use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::ConstraintCompiler, + ir::{Builder, Config, Ext, ExtConst, Felt, Witness}, + }; use sp1_recursion_gnark_ffi::PlonkBn254Prover; #[test] @@ -59,10 +58,7 @@ mod tests { // Testing high degree multiplication. let a_times_b_times_c: Felt<_> = builder.eval(a_val * b_val * a_val * b_val * a_val * b_val); - builder.assert_felt_eq( - a_times_b_times_c, - a_val * b_val * a_val * b_val * a_val * b_val, - ); + builder.assert_felt_eq(a_times_b_times_c, a_val * b_val * a_val * b_val * a_val * b_val); let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); @@ -107,10 +103,7 @@ mod tests { // Testing large linear combination. let dot_product: Ext<_, _> = builder.eval(a * a + b * b + a * b); - builder.assert_ext_eq( - dot_product, - (a_val * a_val + b_val * b_val + a_val * b_val).cons(), - ); + builder.assert_ext_eq(dot_product, (a_val * a_val + b_val * b_val + a_val * b_val).cons()); // Testing high degree multiplication. let a_times_b_times_c: Ext<_, _> = builder.eval(a * b * a * b * a * b); diff --git a/recursion/circuit/src/mmcs.rs b/crates/recursion/circuit/src/mmcs.rs similarity index 73% rename from recursion/circuit/src/mmcs.rs rename to crates/recursion/circuit/src/mmcs.rs index ef6aacb4ae..0847e02c5f 100644 --- a/recursion/circuit/src/mmcs.rs +++ b/crates/recursion/circuit/src/mmcs.rs @@ -13,29 +13,18 @@ pub fn verify_batch( opened_values: Vec>>>, proof: Vec>, ) { - let mut heights_tallest_first = dimensions - .iter() - .enumerate() - .sorted_by_key(|(_, dims)| Reverse(dims.height)) - .peekable(); + let mut heights_tallest_first = + dimensions.iter().enumerate().sorted_by_key(|(_, dims)| Reverse(dims.height)).peekable(); - let mut curr_height_padded = heights_tallest_first - .peek() - .unwrap() - .1 - .height - .next_power_of_two(); + let mut curr_height_padded = heights_tallest_first.peek().unwrap().1.height.next_power_of_two(); let ext_slice: Vec>> = heights_tallest_first .peeking_take_while(|(_, dims)| dims.height.next_power_of_two() == curr_height_padded) .flat_map(|(i, _)| opened_values[i].as_slice()) .cloned() .collect::>(); - let felt_slice: Vec> = ext_slice - .iter() - .flat_map(|ext| ext.as_slice()) - .cloned() - .collect::>(); + let felt_slice: Vec> = + ext_slice.iter().flat_map(|ext| ext.as_slice()).cloned().collect::>(); let mut root = builder.p2_hash(&felt_slice); for (i, sibling) in proof.iter().enumerate() { @@ -57,11 +46,8 @@ pub fn verify_batch( .flat_map(|(i, _)| opened_values[i].as_slice()) .cloned() .collect::>(); - let felt_slice: Vec> = ext_slice - .iter() - .flat_map(|ext| ext.as_slice()) - .cloned() - .collect::>(); + let felt_slice: Vec> = + ext_slice.iter().flat_map(|ext| ext.as_slice()).cloned().collect::>(); let next_height_openings_digest = builder.p2_hash(&felt_slice); root = builder.p2_compress([root, next_height_openings_digest]); } diff --git a/recursion/circuit/src/poseidon2.rs b/crates/recursion/circuit/src/poseidon2.rs similarity index 86% rename from recursion/circuit/src/poseidon2.rs rename to crates/recursion/circuit/src/poseidon2.rs index 792754014d..ffa482057f 100644 --- a/recursion/circuit/src/poseidon2.rs +++ b/crates/recursion/circuit/src/poseidon2.rs @@ -3,16 +3,10 @@ use std::array; use itertools::Itertools; -use p3_field::AbstractField; -use p3_field::Field; -use sp1_recursion_compiler::ir::Felt; -use sp1_recursion_compiler::ir::{Builder, Config, DslIr, Var}; +use p3_field::{AbstractField, Field}; +use sp1_recursion_compiler::ir::{Builder, Config, DslIr, Felt, Var}; -use crate::challenger::reduce_32; -use crate::types::OuterDigestVariable; -use crate::DIGEST_SIZE; -use crate::RATE; -use crate::SPONGE_SIZE; +use crate::{challenger::reduce_32, types::OuterDigestVariable, DIGEST_SIZE, RATE, SPONGE_SIZE}; pub trait Poseidon2CircuitBuilder { fn p2_permute_mut(&mut self, state: [Var; SPONGE_SIZE]); @@ -31,11 +25,8 @@ impl Poseidon2CircuitBuilder for Builder { assert!(C::N::bits() == p3_bn254_fr::Bn254Fr::bits()); assert!(C::F::bits() == p3_baby_bear::BabyBear::bits()); let num_f_elms = C::N::bits() / C::F::bits(); - let mut state: [Var; SPONGE_SIZE] = [ - self.eval(C::N::zero()), - self.eval(C::N::zero()), - self.eval(C::N::zero()), - ]; + let mut state: [Var; SPONGE_SIZE] = + [self.eval(C::N::zero()), self.eval(C::N::zero()), self.eval(C::N::zero())]; for block_chunk in &input.iter().chunks(RATE) { for (chunk_id, chunk) in (&block_chunk.chunks(num_f_elms)).into_iter().enumerate() { let chunk = chunk.collect_vec().into_iter().copied().collect::>(); @@ -48,27 +39,21 @@ impl Poseidon2CircuitBuilder for Builder { } fn p2_compress(&mut self, input: [OuterDigestVariable; 2]) -> OuterDigestVariable { - let state: [Var; SPONGE_SIZE] = [ - self.eval(input[0][0]), - self.eval(input[1][0]), - self.eval(C::N::zero()), - ]; + let state: [Var; SPONGE_SIZE] = + [self.eval(input[0][0]), self.eval(input[1][0]), self.eval(C::N::zero())]; self.p2_permute_mut(state); [state[0]; DIGEST_SIZE] } fn p2_babybear_permute_mut(&mut self, state: [Felt; 16]) { - self.push(DslIr::CircuitPoseidon2PermuteBabyBear(state)); + self.push(DslIr::CircuitPoseidon2PermuteBabyBear(Box::new(state))); } fn p2_babybear_hash(&mut self, input: &[Felt]) -> [Felt; 8] { let mut state: [Felt; 16] = array::from_fn(|_| self.eval(C::F::zero())); for block_chunk in &input.iter().chunks(8) { - state - .iter_mut() - .zip(block_chunk) - .for_each(|(s, i)| *s = self.eval(*i)); + state.iter_mut().zip(block_chunk).for_each(|(s, i)| *s = self.eval(*i)); self.p2_babybear_permute_mut(state); } @@ -82,17 +67,17 @@ pub mod tests { use p3_bn254_fr::Bn254Fr; use p3_field::AbstractField; use p3_symmetric::{CryptographicHasher, Permutation, PseudoCompressionFunction}; - use rand::thread_rng; - use rand::Rng; - use sp1_core::utils::{inner_perm, InnerHash}; - use sp1_recursion_compiler::config::OuterConfig; - use sp1_recursion_compiler::constraints::ConstraintCompiler; - use sp1_recursion_compiler::ir::{Builder, Felt, Var, Witness}; + use rand::{thread_rng, Rng}; + use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::ConstraintCompiler, + ir::{Builder, Felt, Var, Witness}, + }; use sp1_recursion_core::stark::config::{outer_perm, OuterCompress, OuterHash}; use sp1_recursion_gnark_ffi::PlonkBn254Prover; + use sp1_stark::{inner_perm, InnerHash}; - use crate::poseidon2::Poseidon2CircuitBuilder; - use crate::types::OuterDigestVariable; + use crate::{poseidon2::Poseidon2CircuitBuilder, types::OuterDigestVariable}; #[test] fn test_p2_permute_mut() { diff --git a/recursion/circuit/src/stark.rs b/crates/recursion/circuit/src/stark.rs similarity index 58% rename from recursion/circuit/src/stark.rs rename to crates/recursion/circuit/src/stark.rs index c2986c62a4..6c30bdb468 100644 --- a/recursion/circuit/src/stark.rs +++ b/crates/recursion/circuit/src/stark.rs @@ -1,37 +1,48 @@ -use std::borrow::Borrow; -use std::marker::PhantomData; - -use crate::fri::verify_two_adic_pcs; -use crate::poseidon2::Poseidon2CircuitBuilder; -use crate::types::OuterDigestVariable; -use crate::utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}; -use crate::witness::Witnessable; +use std::{borrow::Borrow, fmt::Debug, marker::PhantomData}; + +use crate::{ + fri::verify_two_adic_pcs, + poseidon2::Poseidon2CircuitBuilder, + types::OuterDigestVariable, + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + witness::Witnessable, +}; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::{AbstractField, TwoAdicField}; -use sp1_core::stark::{Com, ShardProof, PROOF_MAX_NUM_PVS}; -use sp1_core::{ - air::MachineAir, - stark::{ShardCommitment, StarkGenericConfig, StarkMachine, StarkVerifyingKey}, +use p3_util::log2_strict_usize; +use sp1_core_machine::utils::{Span, SpanBuilder, SpanBuilderError}; +use sp1_recursion_compiler::{ + config::OuterConfig, + constraints::{Constraint, ConstraintCompiler}, + ir::{Builder, Config, DslIr, Ext, Felt, Usize, Var, Witness}, + prelude::SymbolicVar, +}; +use sp1_recursion_core::{ + air::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH}, + stark::{ + config::{outer_fri_config_with_blowup, BabyBearPoseidon2Outer}, + utils::sp1_dev_mode, + RecursionAirWideDeg17, + }, +}; +use sp1_recursion_program::{ + commit::PolynomialSpaceVariable, stark::RecursiveVerifierConstraintFolder, + types::QuotientDataValues, +}; + +use sp1_stark::{ + air::MachineAir, Com, ShardCommitment, ShardProof, StarkGenericConfig, StarkMachine, + StarkVerifyingKey, PROOF_MAX_NUM_PVS, +}; + +use crate::{ + challenger::MultiField32ChallengerVariable, + domain::{new_coset, TwoAdicMultiplicativeCosetVariable}, + types::{RecursionShardProofVariable, TwoAdicPcsMatsVariable, TwoAdicPcsRoundVariable}, }; -use sp1_recursion_compiler::config::OuterConfig; -use sp1_recursion_compiler::constraints::{Constraint, ConstraintCompiler}; -use sp1_recursion_compiler::ir::{Builder, Config, Ext, Felt, Var}; -use sp1_recursion_compiler::ir::{Usize, Witness}; -use sp1_recursion_compiler::prelude::SymbolicVar; -use sp1_recursion_core::air::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH}; -use sp1_recursion_core::stark::config::{outer_fri_config, BabyBearPoseidon2Outer}; -use sp1_recursion_core::stark::RecursionAirWideDeg17; -use sp1_recursion_program::commit::PolynomialSpaceVariable; -use sp1_recursion_program::stark::RecursiveVerifierConstraintFolder; -use sp1_recursion_program::types::QuotientDataValues; - -use crate::domain::{new_coset, TwoAdicMultiplicativeCosetVariable}; -use crate::types::TwoAdicPcsMatsVariable; -use crate::types::TwoAdicPcsRoundVariable; -use crate::{challenger::MultiField32ChallengerVariable, types::RecursionShardProofVariable}; #[derive(Debug, Clone, Copy)] pub struct StarkVerifierCircuit { @@ -46,7 +57,7 @@ where Domain = TwoAdicMultiplicativeCoset, >, { - pub fn verify_shard( + pub fn verify_shard( builder: &mut Builder, vk: &StarkVerifyingKey, machine: &StarkMachine, @@ -62,21 +73,12 @@ where Com: Into<[Bn254Fr; 1]>, SymbolicVar<::N>: From, { - let RecursionShardProofVariable { - commitment, - opened_values, - .. - } = proof; - - let ShardCommitment { - main_commit, - permutation_commit, - quotient_commit, - } = commitment; - - let permutation_challenges = (0..2) - .map(|_| challenger.sample_ext(builder)) - .collect::>(); + let RecursionShardProofVariable { commitment, opened_values, .. } = proof; + + let ShardCommitment { main_commit, permutation_commit, quotient_commit } = commitment; + + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext(builder)).collect::>(); challenger.observe_commitment(builder, *permutation_commit); @@ -90,7 +92,6 @@ where let mut trace_domains = Vec::new(); let mut quotient_domains = Vec::new(); - let mut prep_mats: Vec> = Vec::new(); let mut main_mats: Vec> = Vec::new(); let mut perm_mats: Vec> = Vec::new(); @@ -98,45 +99,41 @@ where let qc_points = vec![zeta]; - for (name, domain, _) in vk.chip_information.iter() { - let chip_idx = machine - .chips() - .iter() - .rposition(|chip| &chip.name() == name) - .unwrap(); - let index = sorted_indices[chip_idx]; - let opening = &opened_values.chips[index]; - - let domain_var: TwoAdicMultiplicativeCosetVariable<_> = builder.constant(*domain); - - let mut trace_points = Vec::new(); - let zeta_next = domain_var.next_point(builder, zeta); - - trace_points.push(zeta); - trace_points.push(zeta_next); - - let prep_values = vec![ - opening.preprocessed.local.clone(), - opening.preprocessed.next.clone(), - ]; - let prep_mat = TwoAdicPcsMatsVariable:: { - domain: *domain, - points: trace_points.clone(), - values: prep_values, - }; - prep_mats.push(prep_mat); - } + let prep_mats: Vec> = vk + .chip_information + .iter() + .map(|(name, domain, _)| { + let chip_idx = + machine.chips().iter().rposition(|chip| &chip.name() == name).unwrap(); + let index = sorted_indices[chip_idx]; + let opening = &opened_values.chips[index]; + + let domain_var: TwoAdicMultiplicativeCosetVariable<_> = builder.constant(*domain); + + let mut trace_points = Vec::new(); + let zeta_next = domain_var.next_point(builder, zeta); + + trace_points.push(zeta); + trace_points.push(zeta_next); + + let prep_values = + vec![opening.preprocessed.local.clone(), opening.preprocessed.next.clone()]; + TwoAdicPcsMatsVariable:: { + domain: *domain, + points: trace_points.clone(), + values: prep_values, + } + }) + .collect::>(); - for i in 0..num_shard_chips { + (0..num_shard_chips).for_each(|i| { let opening = &opened_values.chips[i]; let log_quotient_degree = chip_quotient_data[i].log_quotient_degree; let domain = new_coset(builder, opening.log_degree); - trace_domains.push(domain.clone()); let log_quotient_size = opening.log_degree + log_quotient_degree; let quotient_domain = domain.create_disjoint_domain(builder, Usize::Const(log_quotient_size), None); - quotient_domains.push(quotient_domain.clone()); let mut trace_points = Vec::new(); let zeta_next = domain.next_point(builder, zeta); @@ -145,19 +142,13 @@ where let main_values = vec![opening.main.local.clone(), opening.main.next.clone()]; let main_mat = TwoAdicPcsMatsVariable:: { - domain: TwoAdicMultiplicativeCoset { - log_n: domain.log_n, - shift: domain.shift, - }, + domain: TwoAdicMultiplicativeCoset { log_n: domain.log_n, shift: domain.shift }, values: main_values, points: trace_points.clone(), }; - main_mats.push(main_mat); - let perm_values = vec![ - opening.permutation.local.clone(), - opening.permutation.next.clone(), - ]; + let perm_values = + vec![opening.permutation.local.clone(), opening.permutation.next.clone()]; let perm_mat = TwoAdicPcsMatsVariable:: { domain: TwoAdicMultiplicativeCoset { log_n: domain.clone().log_n, @@ -166,69 +157,64 @@ where values: perm_values, points: trace_points, }; - perm_mats.push(perm_mat); - let qc_domains = quotient_domain.split_domains_const(builder, log_quotient_degree); - for (j, qc_dom) in qc_domains.into_iter().enumerate() { - let qc_vals_array = opening.quotient[j].clone(); - let qc_values = vec![qc_vals_array]; - let qc_mat = TwoAdicPcsMatsVariable:: { + let qc_mats = quotient_domain + .split_domains_const(builder, log_quotient_degree) + .into_iter() + .enumerate() + .map(|(j, qc_dom)| TwoAdicPcsMatsVariable:: { domain: TwoAdicMultiplicativeCoset { log_n: qc_dom.clone().log_n, shift: qc_dom.clone().shift, }, - values: qc_values, + values: vec![opening.quotient[j].clone()], points: qc_points.clone(), - }; - quotient_mats.push(qc_mat); - } - } + }); + + trace_domains.push(domain.clone()); + quotient_domains.push(quotient_domain.clone()); + main_mats.push(main_mat); + perm_mats.push(perm_mat); + quotient_mats.extend(qc_mats); + }); let mut rounds = Vec::new(); let prep_commit_val: [Bn254Fr; 1] = vk.commit.clone().into(); let prep_commit: OuterDigestVariable = [builder.eval(prep_commit_val[0])]; - let prep_round = TwoAdicPcsRoundVariable { - batch_commit: prep_commit, - mats: prep_mats, - }; - let main_round = TwoAdicPcsRoundVariable { - batch_commit: *main_commit, - mats: main_mats, - }; - let perm_round = TwoAdicPcsRoundVariable { - batch_commit: *permutation_commit, - mats: perm_mats, - }; - let quotient_round = TwoAdicPcsRoundVariable { - batch_commit: *quotient_commit, - mats: quotient_mats, - }; + let prep_round = TwoAdicPcsRoundVariable { batch_commit: prep_commit, mats: prep_mats }; + let main_round = TwoAdicPcsRoundVariable { batch_commit: *main_commit, mats: main_mats }; + let perm_round = + TwoAdicPcsRoundVariable { batch_commit: *permutation_commit, mats: perm_mats }; + let quotient_round = + TwoAdicPcsRoundVariable { batch_commit: *quotient_commit, mats: quotient_mats }; rounds.push(prep_round); rounds.push(main_round); rounds.push(perm_round); rounds.push(quotient_round); - let config = outer_fri_config(); + let config = outer_fri_config_with_blowup(log2_strict_usize(DEGREE - 1)); verify_two_adic_pcs(builder, &config, &proof.opening_proof, challenger, rounds); - for (i, sorted_chip) in sorted_chips.iter().enumerate() { - for chip in machine.chips() { - if chip.name() == *sorted_chip { - let values = &opened_values.chips[i]; - let trace_domain = &trace_domains[i]; - let quotient_domain = "ient_domains[i]; - let qc_domains = - quotient_domain.split_domains_const(builder, chip.log_quotient_degree()); - Self::verify_constraints( - builder, - chip, - values, - proof.public_values.clone(), - trace_domain.clone(), - qc_domains, - zeta, - alpha, - &permutation_challenges, - ); + if !sp1_dev_mode() { + for (i, sorted_chip) in sorted_chips.iter().enumerate() { + for chip in machine.chips() { + if chip.name() == *sorted_chip { + let values = &opened_values.chips[i]; + let trace_domain = &trace_domains[i]; + let quotient_domain = "ient_domains[i]; + let qc_domains = quotient_domain + .split_domains_const(builder, chip.log_quotient_degree()); + Self::verify_constraints( + builder, + chip, + values, + proof.public_values.clone(), + trace_domain.clone(), + qc_domains, + zeta, + alpha, + &permutation_challenges, + ); + } } } } @@ -286,9 +272,7 @@ pub fn build_wrap_circuit( // Convert pv.committed_value_digest into Bn254 let pv_committed_values_digest_bytes: [Felt<_>; 32] = - words_to_bytes(&pv.committed_value_digest) - .try_into() - .unwrap(); + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); let pv_committed_values_digest: Var<_> = babybear_bytes_to_bn254(&mut builder, &pv_committed_values_digest_bytes); @@ -303,23 +287,14 @@ pub fn build_wrap_circuit( let sorted_indices = outer_machine .chips() .iter() - .map(|chip| { - template_proof - .chip_ordering - .get(&chip.name()) - .copied() - .unwrap_or(usize::MAX) - }) + .map(|chip| template_proof.chip_ordering.get(&chip.name()).copied().unwrap_or(usize::MAX)) .collect::>(); let chip_quotient_data = outer_machine .shard_chips_ordered(&template_proof.chip_ordering) .map(|chip| { let log_quotient_degree = chip.log_quotient_degree(); - QuotientDataValues { - log_quotient_degree, - quotient_size: 1 << log_quotient_degree, - } + QuotientDataValues { log_quotient_degree, quotient_size: 1 << log_quotient_degree } }) .collect(); @@ -332,7 +307,7 @@ pub fn build_wrap_circuit( ); challenger.observe_slice(&mut builder, pv_slice); - StarkVerifierCircuit::::verify_shard( + StarkVerifierCircuit::::verify_shard::<_, 17>( &mut builder, wrap_vk, &outer_machine, @@ -357,20 +332,44 @@ pub fn build_wrap_circuit( builder.assert_felt_eq(*expected_elm, *calculated_elm); } + // Print out cycle tracking info. + for line in cycle_tracker(&builder.operations.vec).unwrap().lines() { + println!("{}", line); + } + let mut backend = ConstraintCompiler::::default(); backend.emit(builder.operations) } +pub fn cycle_tracker<'a, C: Config + Debug + 'a>( + operations: impl IntoIterator>, +) -> Result, SpanBuilderError> { + let mut span_builder = SpanBuilder::new("cycle_tracker".to_string()); + for op in operations.into_iter() { + if let DslIr::CycleTracker(name) = op { + if span_builder.current_span.name != *name { + span_builder.enter(name.to_owned()); + } else { + span_builder.exit().map_err(SpanBuilderError::from)?; + } + } else { + let op_dbg_str = format!("{op:?}"); + let op_name = op_dbg_str + [..op_dbg_str.chars().take_while(|x| x.is_alphanumeric()).count()] + .to_owned(); + span_builder.item(op_name); + } + } + span_builder.finish().map_err(SpanBuilderError::from) +} + #[cfg(test)] pub(crate) mod tests { - use p3_field::PrimeField32; - use sp1_recursion_core::{ - cpu::Instruction, - runtime::{Opcode, RecursionProgram}, - }; + use sp1_recursion_core::{cpu::Instruction, runtime::Opcode}; - pub fn basic_program() -> RecursionProgram { + pub fn basic_program( + ) -> sp1_recursion_core::runtime::RecursionProgram { let zero = [F::zero(); 4]; let one = [F::one(), F::zero(), F::zero(), F::zero()]; let mut instructions = vec![Instruction::new( @@ -409,9 +408,6 @@ pub(crate) mod tests { true, "".to_string(), )); - RecursionProgram:: { - instructions, - traces: vec![None], - } + sp1_recursion_core::runtime::RecursionProgram:: { instructions, traces: vec![None] } } } diff --git a/recursion/circuit/src/types.rs b/crates/recursion/circuit/src/types.rs similarity index 88% rename from recursion/circuit/src/types.rs rename to crates/recursion/circuit/src/types.rs index 562204dcf5..1c39b71a25 100644 --- a/recursion/circuit/src/types.rs +++ b/crates/recursion/circuit/src/types.rs @@ -1,11 +1,9 @@ use p3_air::BaseAir; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::AbstractExtensionField; -use sp1_core::{ - air::MachineAir, - stark::{AirOpenedValues, Chip, ChipOpenedValues, ShardCommitment}, -}; +use p3_matrix::{dense::RowMajorMatrixView, stack::VerticalPair}; use sp1_recursion_compiler::ir::{Array, Builder, Config, Ext, ExtConst, Felt, FromConstant, Var}; +use sp1_stark::{air::MachineAir, AirOpenedValues, Chip, ChipOpenedValues, ShardCommitment}; use crate::DIGEST_SIZE; @@ -105,6 +103,19 @@ impl FromConstant for AirOpenedValuesVariable { } } +impl AirOpenedValuesVariable { + pub fn view( + &self, + ) -> VerticalPair< + RowMajorMatrixView<'_, Ext>, + RowMajorMatrixView<'_, Ext>, + > { + let a = RowMajorMatrixView::new_row(&self.local); + let b = RowMajorMatrixView::new_row(&self.next); + VerticalPair::new(a, b) + } +} + impl FromConstant for ChipOpenedValuesVariable { type Constant = ChipOpenedValues; @@ -143,30 +154,21 @@ impl ChipOpening { where A: MachineAir, { - let mut preprocessed = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut preprocessed = AirOpenedValues { local: vec![], next: vec![] }; let preprocess_width = chip.preprocessed_width(); for i in 0..preprocess_width { preprocessed.local.push(opening.preprocessed.local[i]); preprocessed.next.push(opening.preprocessed.next[i]); } - let mut main = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut main = AirOpenedValues { local: vec![], next: vec![] }; let main_width = chip.width(); for i in 0..main_width { main.local.push(opening.main.local[i]); main.next.push(opening.main.next[i]); } - let mut permutation = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut permutation = AirOpenedValues { local: vec![], next: vec![] }; let permutation_width = C::EF::D * chip.permutation_width(); for i in 0..permutation_width { diff --git a/recursion/circuit/src/utils.rs b/crates/recursion/circuit/src/utils.rs similarity index 98% rename from recursion/circuit/src/utils.rs rename to crates/recursion/circuit/src/utils.rs index 371e694395..e86f0cdc5e 100644 --- a/recursion/circuit/src/utils.rs +++ b/crates/recursion/circuit/src/utils.rs @@ -1,7 +1,7 @@ use p3_field::AbstractField; -use sp1_core::air::Word; use sp1_recursion_compiler::ir::{Builder, Config, Felt, Var}; use sp1_recursion_core::runtime::DIGEST_SIZE; +use sp1_stark::Word; pub fn felt2var(builder: &mut Builder, felt: Felt) -> Var { let bits = builder.num2bits_f(felt); diff --git a/recursion/circuit/src/witness.rs b/crates/recursion/circuit/src/witness.rs similarity index 93% rename from recursion/circuit/src/witness.rs rename to crates/recursion/circuit/src/witness.rs index 19046624f2..7255f43a4e 100644 --- a/recursion/circuit/src/witness.rs +++ b/crates/recursion/circuit/src/witness.rs @@ -1,7 +1,4 @@ use p3_bn254_fr::Bn254Fr; -use sp1_core::stark::{ - AirOpenedValues, ChipOpenedValues, ShardCommitment, ShardOpenedValues, ShardProof, -}; use sp1_recursion_compiler::{ config::OuterConfig, ir::{Builder, Config, Ext, Felt, Var, Witness}, @@ -10,6 +7,9 @@ use sp1_recursion_core::stark::config::{ BabyBearPoseidon2Outer, OuterBatchOpening, OuterChallenge, OuterCommitPhaseStep, OuterDigest, OuterFriProof, OuterPcsProof, OuterQueryProof, OuterVal, }; +use sp1_stark::{ + AirOpenedValues, ChipOpenedValues, ShardCommitment, ShardOpenedValues, ShardProof, +}; use crate::types::{ AirOpenedValuesVariable, BatchOpeningVariable, ChipOpenedValuesVariable, @@ -103,11 +103,7 @@ impl Witnessable for ShardCommitment { let main_commit = self.main_commit.read(builder); let permutation_commit = self.permutation_commit.read(builder); let quotient_commit = self.quotient_commit.read(builder); - ShardCommitment { - main_commit, - permutation_commit, - quotient_commit, - } + ShardCommitment { main_commit, permutation_commit, quotient_commit } } fn write(&self, witness: &mut Witness) { @@ -186,10 +182,7 @@ impl Witnessable for OuterBatchOpening { .map(|a| a.into_iter().map(|b| vec![b]).collect()) .collect(); let opening_proof = self.opening_proof.read(builder); - BatchOpeningVariable { - opened_values, - opening_proof, - } + BatchOpeningVariable { opened_values, opening_proof } } fn write(&self, witness: &mut Witness) { @@ -206,10 +199,7 @@ impl Witnessable for OuterCommitPhaseStep { fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { let sibling_value = self.sibling_value.read(builder); let opening_proof = self.opening_proof.read(builder); - FriCommitPhaseProofStepVariable { - sibling_value, - opening_proof, - } + FriCommitPhaseProofStepVariable { sibling_value, opening_proof } } fn write(&self, witness: &mut Witness) { @@ -224,9 +214,7 @@ impl Witnessable for OuterQueryProof { fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { let commit_phase_openings = self.commit_phase_openings.read(builder); - FriQueryProofVariable { - commit_phase_openings, - } + FriQueryProofVariable { commit_phase_openings } } fn write(&self, witness: &mut Witness) { @@ -250,12 +238,7 @@ impl Witnessable for OuterFriProof { let query_proofs = self.query_proofs.read(builder); let final_poly = self.final_poly.read(builder); let pow_witness = self.pow_witness.read(builder); - FriProofVariable { - commit_phase_commits, - query_proofs, - final_poly, - pow_witness, - } + FriProofVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } } fn write(&self, witness: &mut Witness) { @@ -275,10 +258,7 @@ impl Witnessable for OuterPcsProof { fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { let fri_proof = self.fri_proof.read(builder); let query_openings = self.query_openings.read(builder); - TwoAdicPcsProofVariable { - fri_proof, - query_openings, - } + TwoAdicPcsProofVariable { fri_proof, query_openings } } fn write(&self, witness: &mut Witness) { @@ -304,12 +284,7 @@ impl Witnessable for ShardProof { let public_values = self.public_values.read(builder); let public_values = builder.vec(public_values); - RecursionShardProofVariable { - commitment, - opened_values, - opening_proof, - public_values, - } + RecursionShardProofVariable { commitment, opened_values, opening_proof, public_values } } fn write(&self, witness: &mut Witness) { diff --git a/recursion/compiler/CHANGELOG.md b/crates/recursion/compiler/CHANGELOG.md similarity index 100% rename from recursion/compiler/CHANGELOG.md rename to crates/recursion/compiler/CHANGELOG.md diff --git a/recursion/compiler/Cargo.toml b/crates/recursion/compiler/Cargo.toml similarity index 78% rename from recursion/compiler/Cargo.toml rename to crates/recursion/compiler/Cargo.toml index 56ae5cf40e..839273cab7 100644 --- a/recursion/compiler/Cargo.toml +++ b/crates/recursion/compiler/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-compiler" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -21,18 +21,27 @@ p3-poseidon2 = { workspace = true } p3-symmetric = { workspace = true } p3-util = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } sp1-primitives = { workspace = true } sp1-recursion-core = { workspace = true } +sp1-recursion-core-v2 = { workspace = true } sp1-recursion-derive = { workspace = true } +sp1-stark = { workspace = true } itertools = "0.13.0" serde = { version = "1.0.204", features = ["derive"] } backtrace = "0.3.71" tracing = "0.1.40" +rayon = "1.10.0" +vec_map = "0.8.2" [dev-dependencies] p3-challenger = { workspace = true } p3-dft = { workspace = true } p3-merkle-tree = { workspace = true } rand = "0.8.5" +criterion = { version = "0.5.1", features = ["html_reports"] } + +[[bench]] +name = "circuit" +harness = false diff --git a/crates/recursion/compiler/benches/circuit.rs b/crates/recursion/compiler/benches/circuit.rs new file mode 100644 index 0000000000..42d2e94ec5 --- /dev/null +++ b/crates/recursion/compiler/benches/circuit.rs @@ -0,0 +1,85 @@ +use std::time::Duration; + +use criterion::*; +use p3_symmetric::Permutation; +use rand::{rngs::StdRng, Rng, SeedableRng}; + +use sp1_recursion_compiler::{ + asm::{AsmBuilder, AsmConfig}, + circuit::*, + ir::{DslIr, TracedVec}, + prelude::Felt, +}; +use sp1_recursion_core_v2::chips::poseidon2_wide::WIDTH; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, inner_perm, StarkGenericConfig}; + +type SC = BabyBearPoseidon2; +type F = ::Val; +type EF = ::Challenge; +type C = AsmConfig; + +fn poseidon_program() -> TracedVec> { + let mut builder = AsmBuilder::::default(); + let mut rng = StdRng::seed_from_u64(0xCAFEDA7E) + .sample_iter::<[F; WIDTH], _>(rand::distributions::Standard); + for _ in 0..100 { + let input_1: [F; WIDTH] = rng.next().unwrap(); + let output_1 = inner_perm().permute(input_1); + + let input_1_felts = input_1.map(|x| builder.eval(x)); + let output_1_felts = builder.poseidon2_permute_v2(input_1_felts); + let expected: [Felt<_>; WIDTH] = output_1.map(|x| builder.eval(x)); + for (lhs, rhs) in output_1_felts.into_iter().zip(expected) { + builder.assert_felt_eq(lhs, rhs); + } + } + builder.operations +} + +#[allow(dead_code)] +fn compile_one(c: &mut Criterion) { + let input = { + let mut ops = poseidon_program().vec; + ops.truncate(100); + ops + }; + + c.bench_with_input( + BenchmarkId::new("compile_one", format!("{} instructions", input.len())), + &input, + |b, operations| { + let mut compiler = AsmCompiler::>::default(); + b.iter(|| { + for instr in operations.iter().cloned() { + compiler.compile_one(std::hint::black_box(instr), drop); + } + compiler.next_addr = Default::default(); + compiler.virtual_to_physical.clear(); + compiler.consts.clear(); + compiler.addr_to_mult.clear(); + }) + }, + ); +} + +fn compile(c: &mut Criterion) { + let input = poseidon_program(); + + c.bench_with_input( + BenchmarkId::new("compile", format!("{} instructions", input.vec.len())), + &input, + |b, operations| { + let mut compiler = AsmCompiler::>::default(); + b.iter(|| { + compiler.compile(operations.clone()); + }) + }, + ); +} + +criterion_group! { + name = benches; + config = Criterion::default().measurement_time(Duration::from_secs(60)); + targets = compile +} +criterion_main!(benches); diff --git a/recursion/compiler/examples/fibonacci.rs b/crates/recursion/compiler/examples/fibonacci.rs similarity index 91% rename from recursion/compiler/examples/fibonacci.rs rename to crates/recursion/compiler/examples/fibonacci.rs index 57cd15cbca..e92b2fde93 100644 --- a/recursion/compiler/examples/fibonacci.rs +++ b/crates/recursion/compiler/examples/fibonacci.rs @@ -1,9 +1,10 @@ use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::ir::{Felt, Var}; +use sp1_recursion_compiler::{ + asm::AsmBuilder, + ir::{Felt, Var}, +}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; fn fibonacci(n: u32) -> u32 { if n == 0 { diff --git a/recursion/compiler/src/asm/builder.rs b/crates/recursion/compiler/src/asm/builder.rs similarity index 100% rename from recursion/compiler/src/asm/builder.rs rename to crates/recursion/compiler/src/asm/builder.rs diff --git a/recursion/compiler/src/asm/code.rs b/crates/recursion/compiler/src/asm/code.rs similarity index 89% rename from recursion/compiler/src/asm/code.rs rename to crates/recursion/compiler/src/asm/code.rs index be067020f2..026186ac96 100644 --- a/recursion/compiler/src/asm/code.rs +++ b/crates/recursion/compiler/src/asm/code.rs @@ -1,8 +1,6 @@ -use alloc::collections::BTreeMap; -use alloc::format; +use alloc::{collections::BTreeMap, format}; use backtrace::Backtrace; -use core::fmt; -use core::fmt::Display; +use core::{fmt, fmt::Display}; use p3_field::{ExtensionField, PrimeField32}; use sp1_recursion_core::runtime::RecursionProgram; @@ -74,10 +72,7 @@ impl> AssemblyCode { } } - RecursionProgram { - instructions: machine_code, - traces, - } + RecursionProgram { instructions: machine_code, traces } } } @@ -87,9 +82,7 @@ impl> Display for AssemblyCode { writeln!( f, "{}:", - self.labels - .get(&F::from_canonical_u32(i as u32)) - .unwrap_or(&format!(".L{}", i)) + self.labels.get(&F::from_canonical_u32(i as u32)).unwrap_or(&format!(".L{}", i)) )?; for instruction in &block.0 { write!(f, " ")?; diff --git a/recursion/compiler/src/asm/compiler.rs b/crates/recursion/compiler/src/asm/compiler.rs similarity index 88% rename from recursion/compiler/src/asm/compiler.rs rename to crates/recursion/compiler/src/asm/compiler.rs index f2db872bae..fb0450444e 100644 --- a/recursion/compiler/src/asm/compiler.rs +++ b/crates/recursion/compiler/src/asm/compiler.rs @@ -1,24 +1,17 @@ -use alloc::collections::BTreeMap; -use alloc::vec; +use alloc::{collections::BTreeMap, vec}; use backtrace::Backtrace; -use sp1_recursion_core::runtime::HEAP_PTR; -use sp1_recursion_core::runtime::HEAP_START_ADDRESS; +use sp1_recursion_core::runtime::{HEAP_PTR, HEAP_START_ADDRESS}; use std::collections::BTreeSet; -use p3_field::ExtensionField; -use p3_field::PrimeField32; -use p3_field::TwoAdicField; +use p3_field::{ExtensionField, PrimeField32, TwoAdicField}; use sp1_recursion_core::runtime::RecursionProgram; -use super::config::AsmConfig; -use super::IndexTriple; -use super::ValueOrConst; -use super::{AssemblyCode, BasicBlock}; -use crate::asm::AsmInstruction; -use crate::ir::Array; -use crate::ir::Usize; -use crate::ir::{DslIr, Ext, Felt, Ptr, Var}; -use crate::prelude::TracedVec; +use super::{config::AsmConfig, AssemblyCode, BasicBlock, IndexTriple, ValueOrConst}; +use crate::{ + asm::AsmInstruction, + ir::{Array, DslIr, Ext, Felt, Ptr, Usize, Var}, + prelude::TracedVec, +}; /// The zero address. pub(crate) const ZERO: i32 = 0; @@ -135,10 +128,7 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::AddEI(dst.fp(), lhs.fp(), rhs), trace); } DslIr::AddEFI(dst, lhs, rhs) => { - self.push( - AsmInstruction::AddEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), - trace, - ); + self.push(AsmInstruction::AddEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), trace); } DslIr::SubV(dst, lhs, rhs) => { self.push(AsmInstruction::SubF(dst.fp(), lhs.fp(), rhs.fp()), trace); @@ -183,10 +173,7 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::DivE(dst.fp(), lhs.fp(), rhs.fp()), trace); } DslIr::DivEFI(dst, lhs, rhs) => { - self.push( - AsmInstruction::DivEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), - trace, - ); + self.push(AsmInstruction::DivEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), trace); } DslIr::DivEIN(dst, lhs, rhs) => { self.push(AsmInstruction::DivEIN(dst.fp(), lhs, rhs.fp()), trace); @@ -210,10 +197,7 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::SubE(dst.fp(), lhs.fp(), rhs.fp()), trace); } DslIr::SubEFI(dst, lhs, rhs) => { - self.push( - AsmInstruction::SubEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), - trace, - ); + self.push(AsmInstruction::SubEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), trace); } DslIr::SubEIN(dst, lhs, rhs) => { self.push(AsmInstruction::SubEIN(dst.fp(), lhs, rhs.fp()), trace); @@ -225,10 +209,7 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::SubEI(dst.fp(), lhs.fp(), rhs), trace); } DslIr::NegE(dst, src) => { - self.push( - AsmInstruction::SubEIN(dst.fp(), EF::zero(), src.fp()), - trace, - ); + self.push(AsmInstruction::SubEIN(dst.fp(), EF::zero(), src.fp()), trace); } DslIr::MulV(dst, lhs, rhs) => { self.push(AsmInstruction::MulF(dst.fp(), lhs.fp(), rhs.fp()), trace); @@ -252,12 +233,10 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::MulE(dst.fp(), lhs.fp(), rhs.fp()), trace); } DslIr::MulEFI(dst, lhs, rhs) => { - self.push( - AsmInstruction::MulEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), - trace, - ); + self.push(AsmInstruction::MulEI(dst.fp(), lhs.fp(), EF::from_base(rhs)), trace); } - DslIr::IfEq(lhs, rhs, then_block, else_block) => { + DslIr::IfEq(data) => { + let (lhs, rhs, then_block, else_block) = *data; let if_compiler = IfCompiler { compiler: self, lhs: lhs.fp(), @@ -273,7 +252,8 @@ impl + TwoAdicField> AsmCo ); } } - DslIr::IfNe(lhs, rhs, then_block, else_block) => { + DslIr::IfNe(data) => { + let (lhs, rhs, then_block, else_block) = *data; let if_compiler = IfCompiler { compiler: self, lhs: lhs.fp(), @@ -289,7 +269,8 @@ impl + TwoAdicField> AsmCo ); } } - DslIr::IfEqI(lhs, rhs, then_block, else_block) => { + DslIr::IfEqI(data) => { + let (lhs, rhs, then_block, else_block) = *data; let if_compiler = IfCompiler { compiler: self, lhs: lhs.fp(), @@ -305,7 +286,8 @@ impl + TwoAdicField> AsmCo ); } } - DslIr::IfNeI(lhs, rhs, then_block, else_block) => { + DslIr::IfNeI(data) => { + let (lhs, rhs, then_block, else_block) = *data; let if_compiler = IfCompiler { compiler: self, lhs: lhs.fp(), @@ -327,14 +309,10 @@ impl + TwoAdicField> AsmCo self.contains_break.insert(current_block); self.push(AsmInstruction::Break(label), trace); } - DslIr::For(start, end, step_size, loop_var, block) => { - let for_compiler = ForCompiler { - compiler: self, - start, - end, - step_size, - loop_var, - }; + DslIr::For(data) => { + let (start, end, step_size, loop_var, block) = *data; + let for_compiler = + ForCompiler { compiler: self, start, end, step_size, loop_var }; for_compiler.for_each(move |_, builder| builder.build(block)); } DslIr::AssertEqV(lhs, rhs) => { @@ -467,7 +445,7 @@ impl + TwoAdicField> AsmCo } _ => unimplemented!(), }, - DslIr::Poseidon2PermuteBabyBear(dst, src) => match (dst, src) { + DslIr::Poseidon2PermuteBabyBear(data) => match *data { (Array::Dyn(dst, _), Array::Dyn(src, _)) => { self.push(AsmInstruction::Poseidon2Permute(dst.fp(), src.fp()), trace) } @@ -503,20 +481,14 @@ impl + TwoAdicField> AsmCo unimplemented!(); } } - DslIr::Poseidon2CompressBabyBear(result, left, right) => { - match (result, left, right) { - (Array::Dyn(result, _), Array::Dyn(left, _), Array::Dyn(right, _)) => self - .push( - AsmInstruction::Poseidon2Compress( - result.fp(), - left.fp(), - right.fp(), - ), - trace, - ), - _ => unimplemented!(), - } - } + DslIr::Poseidon2CompressBabyBear(data) => match *data { + (Array::Dyn(result, _), Array::Dyn(left, _), Array::Dyn(right, _)) => self + .push( + AsmInstruction::Poseidon2Compress(result.fp(), left.fp(), right.fp()), + trace, + ), + _ => unimplemented!(), + }, DslIr::Poseidon2AbsorbBabyBear(p2_hash_and_absorb_num, input) => match input { Array::Dyn(input, input_size) => { if let Usize::Var(input_size) = input_size { @@ -550,10 +522,7 @@ impl + TwoAdicField> AsmCo self.push(AsmInstruction::RegisterPublicValue(val.fp()), trace); } DslIr::LessThan(dst, left, right) => { - self.push( - AsmInstruction::LessThan(dst.fp(), left.fp(), right.fp()), - trace, - ); + self.push(AsmInstruction::LessThan(dst.fp(), left.fp(), right.fp()), trace); } DslIr::CycleTracker(name) => { self.push(AsmInstruction::CycleTracker(name.clone()), trace); @@ -578,20 +547,11 @@ impl + TwoAdicField> AsmCo match len { Usize::Const(len) => { let len = F::from_canonical_usize(len); - self.push( - AsmInstruction::AddFI(ptr.fp(), HEAP_PTR, F::zero()), - backtrace.clone(), - ); - self.push( - AsmInstruction::AddFI(HEAP_PTR, HEAP_PTR, len * size), - backtrace, - ); + self.push(AsmInstruction::AddFI(ptr.fp(), HEAP_PTR, F::zero()), backtrace.clone()); + self.push(AsmInstruction::AddFI(HEAP_PTR, HEAP_PTR, len * size), backtrace); } Usize::Var(len) => { - self.push( - AsmInstruction::AddFI(ptr.fp(), HEAP_PTR, F::zero()), - backtrace.clone(), - ); + self.push(AsmInstruction::AddFI(ptr.fp(), HEAP_PTR, F::zero()), backtrace.clone()); self.push(AsmInstruction::MulFI(A0, len.fp(), size), backtrace.clone()); self.push(AsmInstruction::AddF(HEAP_PTR, HEAP_PTR, A0), backtrace); } @@ -605,21 +565,12 @@ impl + TwoAdicField> AsmCo is_eq: bool, backtrace: Option, ) { - let if_compiler = IfCompiler { - compiler: self, - lhs, - rhs, - is_eq, - }; + let if_compiler = IfCompiler { compiler: self, lhs, rhs, is_eq }; if_compiler.then(|builder| builder.push(AsmInstruction::Trap, backtrace)); } pub fn code(self) -> AssemblyCode { - let labels = self - .function_labels - .into_iter() - .map(|(k, v)| (v, k)) - .collect(); + let labels = self.function_labels.into_iter().map(|(k, v)| (v, k)).collect(); AssemblyCode::new(self.basic_blocks, labels) } @@ -650,10 +601,7 @@ impl + TwoAdicField> AsmCo } fn push(&mut self, instruction: AsmInstruction, backtrace: Option) { - self.basic_blocks - .last_mut() - .unwrap() - .push(instruction, backtrace); + self.basic_blocks.last_mut().unwrap().push(instruction, backtrace); } } @@ -671,12 +619,7 @@ impl<'a, F: PrimeField32 + TwoAdicField, EF: ExtensionField + TwoAdicField> where Func: FnOnce(&mut AsmCompiler), { - let Self { - compiler, - lhs, - rhs, - is_eq, - } = self; + let Self { compiler, lhs, rhs, is_eq } = self; // Get the label for the current block. let current_block = compiler.block_label(); @@ -699,12 +642,7 @@ impl<'a, F: PrimeField32 + TwoAdicField, EF: ExtensionField + TwoAdicField> ThenFunc: FnOnce(&mut AsmCompiler), ElseFunc: FnOnce(&mut AsmCompiler), { - let Self { - compiler, - lhs, - rhs, - is_eq, - } = self; + let Self { compiler, lhs, rhs, is_eq } = self; // Get the label for the current block, so we can generate the jump instruction into it. // conditional branc instruction to it, if the condition is not met. @@ -821,9 +759,8 @@ impl<'a, F: PrimeField32 + TwoAdicField, EF: ExtensionField + TwoAdicField> // Replace the break instruction with a jump to the after loop block. for block in self.compiler.contains_break.iter() { - for instruction in self.compiler.basic_blocks[block.as_canonical_u32() as usize] - .0 - .iter_mut() + for instruction in + self.compiler.basic_blocks[block.as_canonical_u32() as usize].0.iter_mut() { if let AsmInstruction::Break(l) = instruction { if *l == break_label { @@ -845,10 +782,8 @@ impl<'a, F: PrimeField32 + TwoAdicField, EF: ExtensionField + TwoAdicField> ); } Usize::Var(var) => { - self.compiler.push( - AsmInstruction::AddFI(self.loop_var.fp(), var.fp(), F::zero()), - None, - ); + self.compiler + .push(AsmInstruction::AddFI(self.loop_var.fp(), var.fp(), F::zero()), None); } } } diff --git a/recursion/compiler/src/asm/config.rs b/crates/recursion/compiler/src/asm/config.rs similarity index 100% rename from recursion/compiler/src/asm/config.rs rename to crates/recursion/compiler/src/asm/config.rs diff --git a/recursion/compiler/src/asm/instruction.rs b/crates/recursion/compiler/src/asm/instruction.rs similarity index 93% rename from recursion/compiler/src/asm/instruction.rs rename to crates/recursion/compiler/src/asm/instruction.rs index 0dc9d5767d..c6f4578db4 100644 --- a/recursion/compiler/src/asm/instruction.rs +++ b/crates/recursion/compiler/src/asm/instruction.rs @@ -1,10 +1,11 @@ -use alloc::collections::BTreeMap; -use alloc::format; +use alloc::{collections::BTreeMap, format}; use core::fmt; use p3_field::{ExtensionField, PrimeField32}; -use sp1_recursion_core::cpu::Instruction; -use sp1_recursion_core::runtime::{canonical_i32_to_field, Opcode, PERMUTATION_WIDTH}; +use sp1_recursion_core::{ + cpu::Instruction, + runtime::{canonical_i32_to_field, Opcode, PERMUTATION_WIDTH}, +}; use super::A0; @@ -188,10 +189,11 @@ pub enum AsmInstruction { CycleTracker(String), - /// ExpReverseBitsLen instruction: (mathematical description) given `x`, `exp`, `len`, bit-reverse the last `len` bits of - /// `exp` and raise `x` to the power of the resulting value. The arguments are a pointer to the - /// addresss at which `x` is located (will be written to with the result), a pointer to the - /// address containing the bits of `exp` stored as a little-endian bit array, and `len`. + /// ExpReverseBitsLen instruction: (mathematical description) given `x`, `exp`, `len`, + /// bit-reverse the last `len` bits of `exp` and raise `x` to the power of the resulting + /// value. The arguments are a pointer to the addresss at which `x` is located (will be + /// written to with the result), a pointer to the address containing the bits of `exp` + /// stored as a little-endian bit array, and `len`. ExpReverseBitsLen(i32, i32, i32), } @@ -202,14 +204,7 @@ impl> AsmInstruction { pub fn to_machine(self, pc: usize, label_to_pc: &BTreeMap) -> Instruction { let i32_f = canonical_i32_to_field::; - let i32_f_arr = |x: i32| { - [ - canonical_i32_to_field::(x), - F::zero(), - F::zero(), - F::zero(), - ] - }; + let i32_f_arr = |x: i32| [canonical_i32_to_field::(x), F::zero(), F::zero(), F::zero()]; let f_u32 = |x: F| [x, F::zero(), F::zero(), F::zero()]; let zero = [F::zero(), F::zero(), F::zero(), F::zero()]; match self { @@ -921,32 +916,16 @@ impl> AsmInstruction { write!(f, "lt ({})fp, {}, {}", dst, left, right,) } AsmInstruction::LoadF(dst, src, index, offset, size) => { - write!( - f, - "lw ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, index, offset, size - ) + write!(f, "lw ({})fp, ({})fp, ({})fp, {}, {}", dst, src, index, offset, size) } AsmInstruction::LoadFI(dst, src, index, offset, size) => { - write!( - f, - "lwi ({})fp, ({})fp, {}, {}, {}", - dst, src, index, offset, size - ) + write!(f, "lwi ({})fp, ({})fp, {}, {}, {}", dst, src, index, offset, size) } AsmInstruction::StoreF(dst, src, index, offset, size) => { - write!( - f, - "sw ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, index, offset, size - ) + write!(f, "sw ({})fp, ({})fp, ({})fp, {}, {}", dst, src, index, offset, size) } AsmInstruction::StoreFI(dst, src, index, offset, size) => { - write!( - f, - "swi ({})fp, ({})fp, {}, {}, {}", - dst, src, index, offset, size - ) + write!(f, "swi ({})fp, ({})fp, {}, {}, {}", dst, src, index, offset, size) } AsmInstruction::AddF(dst, lhs, rhs) => { write!(f, "add ({})fp, ({})fp, ({})fp", dst, lhs, rhs) @@ -979,32 +958,16 @@ impl> AsmInstruction { write!(f, "divin ({})fp, {}, ({})fp", dst, lhs, rhs) } AsmInstruction::LoadE(dst, src, index, offset, size) => { - write!( - f, - "le ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, index, offset, size - ) + write!(f, "le ({})fp, ({})fp, ({})fp, {}, {}", dst, src, index, offset, size) } AsmInstruction::LoadEI(dst, src, index, offset, size) => { - write!( - f, - "lei ({})fp, ({})fp, {}, {}, {}", - dst, src, index, offset, size - ) + write!(f, "lei ({})fp, ({})fp, {}, {}, {}", dst, src, index, offset, size) } AsmInstruction::StoreE(dst, src, index, offset, size) => { - write!( - f, - "se ({})fp, ({})fp, ({})fp, {}, {}", - dst, src, index, offset, size - ) + write!(f, "se ({})fp, ({})fp, ({})fp, {}, {}", dst, src, index, offset, size) } AsmInstruction::StoreEI(dst, src, index, offset, size) => { - write!( - f, - "sei ({})fp, ({})fp, {}, {}, {}", - dst, src, index, offset, size - ) + write!(f, "sei ({})fp, ({})fp, {}, {}, {}", dst, src, index, offset, size) } AsmInstruction::AddE(dst, lhs, rhs) => { write!(f, "eadd ({})fp, ({})fp, ({})fp", dst, lhs, rhs) @@ -1170,11 +1133,7 @@ impl> AsmInstruction { write!(f, "fri_fold ({})fp, ({})fp", m, input_ptr) } AsmInstruction::Poseidon2Compress(result, src1, src2) => { - write!( - f, - "poseidon2_compress ({})fp, {})fp, {})fp", - result, src1, src2 - ) + write!(f, "poseidon2_compress ({})fp, {})fp, {})fp", result, src1, src2) } AsmInstruction::Poseidon2Absorb(hash_and_absorb_num, input_ptr, input_len) => { write!( @@ -1196,11 +1155,7 @@ impl> AsmInstruction { write!(f, "cycle-tracker {}", name) } AsmInstruction::ExpReverseBitsLen(base, ptr, len) => { - write!( - f, - "exp_reverse_bits_len ({})fp, ({})fp, ({})fp", - base, ptr, len - ) + write!(f, "exp_reverse_bits_len ({})fp, ({})fp, ({})fp", base, ptr, len) } } } diff --git a/recursion/compiler/src/asm/mod.rs b/crates/recursion/compiler/src/asm/mod.rs similarity index 100% rename from recursion/compiler/src/asm/mod.rs rename to crates/recursion/compiler/src/asm/mod.rs diff --git a/recursion/compiler/src/asm/utils.rs b/crates/recursion/compiler/src/asm/utils.rs similarity index 100% rename from recursion/compiler/src/asm/utils.rs rename to crates/recursion/compiler/src/asm/utils.rs diff --git a/crates/recursion/compiler/src/circuit/builder.rs b/crates/recursion/compiler/src/circuit/builder.rs new file mode 100644 index 0000000000..cca0788722 --- /dev/null +++ b/crates/recursion/compiler/src/circuit/builder.rs @@ -0,0 +1,179 @@ +//! An implementation of Poseidon2 over BN254. + +use std::iter::repeat; + +use p3_field::{AbstractExtensionField, AbstractField}; +use sp1_recursion_core::air::RecursionPublicValues; + +use crate::prelude::*; +use sp1_recursion_core_v2::{chips::poseidon2_skinny::WIDTH, D, DIGEST_SIZE, HASH_RATE}; + +pub trait CircuitV2Builder { + fn bits2num_v2_f( + &mut self, + bits: impl IntoIterator::F>>, + ) -> Felt; + fn num2bits_v2_f(&mut self, num: Felt, num_bits: usize) -> Vec>; + fn exp_reverse_bits_v2(&mut self, input: Felt, power_bits: Vec>) + -> Felt; + fn poseidon2_permute_v2(&mut self, state: [Felt; WIDTH]) -> [Felt; WIDTH]; + fn poseidon2_hash_v2(&mut self, array: &[Felt]) -> [Felt; DIGEST_SIZE]; + fn poseidon2_compress_v2( + &mut self, + input: impl IntoIterator>, + ) -> [Felt; DIGEST_SIZE]; + fn fri_fold_v2(&mut self, input: CircuitV2FriFoldInput) -> CircuitV2FriFoldOutput; + fn ext2felt_v2(&mut self, ext: Ext) -> [Felt; D]; + fn commit_public_values_v2(&mut self, public_values: RecursionPublicValues>); + fn cycle_tracker_v2_enter(&mut self, name: String); + fn cycle_tracker_v2_exit(&mut self); + fn hint_ext_v2(&mut self) -> Ext; + fn hint_felt_v2(&mut self) -> Felt; + fn hint_exts_v2(&mut self, len: usize) -> Vec>; + fn hint_felts_v2(&mut self, len: usize) -> Vec>; +} + +impl CircuitV2Builder for Builder { + fn bits2num_v2_f( + &mut self, + bits: impl IntoIterator::F>>, + ) -> Felt<::F> { + let mut num: Felt<_> = self.eval(C::F::zero()); + for (i, bit) in bits.into_iter().enumerate() { + // Add `bit * 2^i` to the sum. + num = self.eval(num + bit * C::F::from_wrapped_u32(1 << i)); + } + num + } + + /// Converts a felt to bits inside a circuit. + fn num2bits_v2_f(&mut self, num: Felt, num_bits: usize) -> Vec> { + let output = std::iter::from_fn(|| Some(self.uninit())).take(num_bits).collect::>(); + self.push(DslIr::CircuitV2HintBitsF(output.clone(), num)); + + let x: SymbolicFelt<_> = output + .iter() + .enumerate() + .map(|(i, &bit)| { + self.assert_felt_eq(bit * (bit - C::F::one()), C::F::zero()); + bit * C::F::from_wrapped_u32(1 << i) + }) + .sum(); + + self.assert_felt_eq(x, num); + + output + } + + /// A version of `exp_reverse_bits_len` that uses the ExpReverseBitsLen precompile. + fn exp_reverse_bits_v2( + &mut self, + input: Felt, + power_bits: Vec>, + ) -> Felt { + let output: Felt<_> = self.uninit(); + self.operations.push(DslIr::CircuitV2ExpReverseBits(output, input, power_bits)); + output + } + + /// Applies the Poseidon2 permutation to the given array. + fn poseidon2_permute_v2(&mut self, array: [Felt; WIDTH]) -> [Felt; WIDTH] { + let output: [Felt; WIDTH] = core::array::from_fn(|_| self.uninit()); + self.operations.push(DslIr::CircuitV2Poseidon2PermuteBabyBear(Box::new((output, array)))); + output + } + + /// Applies the Poseidon2 permutation to the given array. + /// + /// Reference: [p3_symmetric::PaddingFreeSponge] + fn poseidon2_hash_v2(&mut self, input: &[Felt]) -> [Felt; DIGEST_SIZE] { + // static_assert(RATE < WIDTH) + let mut state = core::array::from_fn(|_| self.eval(C::F::zero())); + for input_chunk in input.chunks(HASH_RATE) { + state[..input_chunk.len()].copy_from_slice(input_chunk); + state = self.poseidon2_permute_v2(state); + } + let state: [Felt; DIGEST_SIZE] = state[..DIGEST_SIZE].try_into().unwrap(); + state + } + + /// Applies the Poseidon2 compression function to the given array. + /// + /// Reference: [p3_symmetric::TruncatedPermutation] + fn poseidon2_compress_v2( + &mut self, + input: impl IntoIterator>, + ) -> [Felt; DIGEST_SIZE] { + // debug_assert!(DIGEST_SIZE * N <= WIDTH); + let mut pre_iter = input.into_iter().chain(repeat(self.eval(C::F::default()))); + let pre = core::array::from_fn(move |_| pre_iter.next().unwrap()); + let post = self.poseidon2_permute_v2(pre); + let post: [Felt; DIGEST_SIZE] = post[..DIGEST_SIZE].try_into().unwrap(); + post + } + + /// Runs FRI fold. + fn fri_fold_v2(&mut self, input: CircuitV2FriFoldInput) -> CircuitV2FriFoldOutput { + let mut uninit_vec = |len| std::iter::from_fn(|| Some(self.uninit())).take(len).collect(); + let output = CircuitV2FriFoldOutput { + alpha_pow_output: uninit_vec(input.alpha_pow_input.len()), + ro_output: uninit_vec(input.ro_input.len()), + }; + self.operations.push(DslIr::CircuitV2FriFold(Box::new((output.clone(), input)))); + output + } + + /// Decomposes an ext into its felt coordinates. + fn ext2felt_v2(&mut self, ext: Ext) -> [Felt; D] { + let felts = core::array::from_fn(|_| self.uninit()); + self.operations.push(DslIr::CircuitExt2Felt(felts, ext)); + // Verify that the decomposed extension element is correct. + let mut reconstructed_ext: Ext = self.constant(C::EF::zero()); + for i in 0..4 { + let felt = felts[i]; + let monomial: Ext = self.constant(C::EF::monomial(i)); + reconstructed_ext = self.eval(reconstructed_ext + monomial * felt); + } + + self.assert_ext_eq(reconstructed_ext, ext); + + felts + } + + // Commits public values. + fn commit_public_values_v2(&mut self, public_values: RecursionPublicValues>) { + self.operations.push(DslIr::CircuitV2CommitPublicValues(Box::new(public_values))); + } + + fn cycle_tracker_v2_enter(&mut self, name: String) { + self.operations.push(DslIr::CycleTrackerV2Enter(name)); + } + + fn cycle_tracker_v2_exit(&mut self) { + self.operations.push(DslIr::CycleTrackerV2Exit); + } + + /// Hint a single felt. + fn hint_felt_v2(&mut self) -> Felt { + self.hint_felts_v2(1)[0] + } + + /// Hint a single ext. + fn hint_ext_v2(&mut self) -> Ext { + self.hint_exts_v2(1)[0] + } + + /// Hint a vector of felts. + fn hint_felts_v2(&mut self, len: usize) -> Vec> { + let arr = std::iter::from_fn(|| Some(self.uninit())).take(len).collect::>(); + self.operations.push(DslIr::CircuitV2HintFelts(arr.clone())); + arr + } + + /// Hint a vector of exts. + fn hint_exts_v2(&mut self, len: usize) -> Vec> { + let arr = std::iter::from_fn(|| Some(self.uninit())).take(len).collect::>(); + self.operations.push(DslIr::CircuitV2HintExts(arr.clone())); + arr + } +} diff --git a/crates/recursion/compiler/src/circuit/compiler.rs b/crates/recursion/compiler/src/circuit/compiler.rs new file mode 100644 index 0000000000..2d830e53b7 --- /dev/null +++ b/crates/recursion/compiler/src/circuit/compiler.rs @@ -0,0 +1,1144 @@ +use chips::poseidon2_skinny::WIDTH; +use core::fmt::Debug; +use instruction::{FieldEltType, HintBitsInstr, HintExt2FeltsInstr, HintInstr, PrintInstr}; +use p3_field::{ + AbstractExtensionField, AbstractField, Field, PrimeField, PrimeField64, TwoAdicField, +}; +use sp1_core_machine::utils::{sp1_debug_mode, SpanBuilder}; +use sp1_recursion_core::air::{Block, RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; +use sp1_recursion_core_v2::{BaseAluInstr, BaseAluOpcode}; +use std::{borrow::Borrow, collections::HashMap, iter::repeat, mem::transmute}; +use vec_map::VecMap; + +use sp1_recursion_core_v2::*; + +use crate::prelude::*; + +/// The backend for the circuit compiler. +#[derive(Debug, Clone, Default)] +pub struct AsmCompiler { + pub next_addr: C::F, + /// Map the frame pointers of the variables to the "physical" addresses. + pub virtual_to_physical: VecMap>, + /// Map base or extension field constants to "physical" addresses and mults. + pub consts: HashMap, (Address, C::F)>, + /// Map each "physical" address to its read count. + pub addr_to_mult: VecMap, +} + +impl AsmCompiler +where + C::F: PrimeField64, +{ + /// Allocate a fresh address. Checks that the address space is not full. + pub fn alloc(next_addr: &mut C::F) -> Address { + let id = Address(*next_addr); + *next_addr += C::F::one(); + if next_addr.is_zero() { + panic!("out of address space"); + } + id + } + + /// Map `fp` to its existing address without changing its mult. + /// + /// Ensures that `fp` has already been assigned an address. + pub fn read_ghost_vaddr(&mut self, vaddr: usize) -> Address { + self.read_vaddr_internal(vaddr, false) + } + + /// Map `fp` to its existing address and increment its mult. + /// + /// Ensures that `fp` has already been assigned an address. + pub fn read_vaddr(&mut self, vaddr: usize) -> Address { + self.read_vaddr_internal(vaddr, true) + } + + pub fn read_vaddr_internal(&mut self, vaddr: usize, increment_mult: bool) -> Address { + use vec_map::Entry; + match self.virtual_to_physical.entry(vaddr) { + Entry::Vacant(_) => panic!("expected entry: virtual_physical[{:?}]", vaddr), + Entry::Occupied(entry) => { + if increment_mult { + // This is a read, so we increment the mult. + match self.addr_to_mult.get_mut(entry.get().as_usize()) { + Some(mult) => *mult += C::F::one(), + None => panic!("expected entry: virtual_physical[{:?}]", vaddr), + } + } + *entry.into_mut() + } + } + } + + /// Map `fp` to a fresh address and initialize the mult to 0. + /// + /// Ensures that `fp` has not already been written to. + pub fn write_fp(&mut self, vaddr: usize) -> Address { + use vec_map::Entry; + match self.virtual_to_physical.entry(vaddr) { + Entry::Vacant(entry) => { + let addr = Self::alloc(&mut self.next_addr); + // This is a write, so we set the mult to zero. + if let Some(x) = self.addr_to_mult.insert(addr.as_usize(), C::F::zero()) { + panic!("unexpected entry in addr_to_mult: {x:?}"); + } + *entry.insert(addr) + } + Entry::Occupied(entry) => { + panic!("unexpected entry: virtual_to_physical[{:?}] = {:?}", vaddr, entry.get()) + } + } + } + + /// Increment the existing `mult` associated with `addr`. + /// + /// Ensures that `addr` has already been assigned a `mult`. + pub fn read_addr(&mut self, addr: Address) -> &mut C::F { + self.read_addr_internal(addr, true) + } + + /// Retrieves `mult` associated with `addr`. + /// + /// Ensures that `addr` has already been assigned a `mult`. + pub fn read_ghost_addr(&mut self, addr: Address) -> &mut C::F { + self.read_addr_internal(addr, true) + } + + fn read_addr_internal(&mut self, addr: Address, increment_mult: bool) -> &mut C::F { + use vec_map::Entry; + match self.addr_to_mult.entry(addr.as_usize()) { + Entry::Vacant(_) => panic!("expected entry: addr_to_mult[{:?}]", addr.as_usize()), + Entry::Occupied(entry) => { + // This is a read, so we increment the mult. + let mult = entry.into_mut(); + if increment_mult { + *mult += C::F::one(); + } + mult + } + } + } + + /// Associate a `mult` of zero with `addr`. + /// + /// Ensures that `addr` has not already been written to. + pub fn write_addr(&mut self, addr: Address) -> &mut C::F { + use vec_map::Entry; + match self.addr_to_mult.entry(addr.as_usize()) { + Entry::Vacant(entry) => entry.insert(C::F::zero()), + Entry::Occupied(entry) => { + panic!("unexpected entry: addr_to_mult[{:?}] = {:?}", addr.as_usize(), entry.get()) + } + } + } + + /// Read a constant (a.k.a. immediate). + /// + /// Increments the mult, first creating an entry if it does not yet exist. + pub fn read_const(&mut self, imm: Imm) -> Address { + self.consts + .entry(imm) + .and_modify(|(_, x)| *x += C::F::one()) + .or_insert_with(|| (Self::alloc(&mut self.next_addr), C::F::one())) + .0 + } + + /// Read a constant (a.k.a. immediate). + /// + /// Does not increment the mult. Creates an entry if it does not yet exist. + pub fn read_ghost_const(&mut self, imm: Imm) -> Address { + self.consts.entry(imm).or_insert_with(|| (Self::alloc(&mut self.next_addr), C::F::zero())).0 + } + + fn mem_write_const(&mut self, dst: impl Reg, src: Imm) -> Instruction { + Instruction::Mem(MemInstr { + addrs: MemIo { inner: dst.write(self) }, + vals: MemIo { inner: src.as_block() }, + mult: C::F::zero(), + kind: MemAccessKind::Write, + }) + } + + fn base_alu( + &mut self, + opcode: BaseAluOpcode, + dst: impl Reg, + lhs: impl Reg, + rhs: impl Reg, + ) -> Instruction { + Instruction::BaseAlu(BaseAluInstr { + opcode, + mult: C::F::zero(), + addrs: BaseAluIo { out: dst.write(self), in1: lhs.read(self), in2: rhs.read(self) }, + }) + } + + fn ext_alu( + &mut self, + opcode: ExtAluOpcode, + dst: impl Reg, + lhs: impl Reg, + rhs: impl Reg, + ) -> Instruction { + Instruction::ExtAlu(ExtAluInstr { + opcode, + mult: C::F::zero(), + addrs: ExtAluIo { out: dst.write(self), in1: lhs.read(self), in2: rhs.read(self) }, + }) + } + + fn base_assert_eq( + &mut self, + lhs: impl Reg, + rhs: impl Reg, + mut f: impl FnMut(Instruction), + ) { + use BaseAluOpcode::*; + let [diff, out] = core::array::from_fn(|_| Self::alloc(&mut self.next_addr)); + f(self.base_alu(SubF, diff, lhs, rhs)); + f(self.base_alu(DivF, out, diff, Imm::F(C::F::zero()))); + } + + fn base_assert_ne( + &mut self, + lhs: impl Reg, + rhs: impl Reg, + mut f: impl FnMut(Instruction), + ) { + use BaseAluOpcode::*; + let [diff, out] = core::array::from_fn(|_| Self::alloc(&mut self.next_addr)); + + f(self.base_alu(SubF, diff, lhs, rhs)); + f(self.base_alu(DivF, out, Imm::F(C::F::one()), diff)); + } + + fn ext_assert_eq( + &mut self, + lhs: impl Reg, + rhs: impl Reg, + mut f: impl FnMut(Instruction), + ) { + use ExtAluOpcode::*; + let [diff, out] = core::array::from_fn(|_| Self::alloc(&mut self.next_addr)); + + f(self.ext_alu(SubE, diff, lhs, rhs)); + f(self.ext_alu(DivE, out, diff, Imm::EF(C::EF::zero()))); + } + + fn ext_assert_ne( + &mut self, + lhs: impl Reg, + rhs: impl Reg, + mut f: impl FnMut(Instruction), + ) { + use ExtAluOpcode::*; + let [diff, out] = core::array::from_fn(|_| Self::alloc(&mut self.next_addr)); + + f(self.ext_alu(SubE, diff, lhs, rhs)); + f(self.ext_alu(DivE, out, Imm::EF(C::EF::one()), diff)); + } + + fn poseidon2_permute( + &mut self, + dst: [impl Reg; WIDTH], + src: [impl Reg; WIDTH], + ) -> Instruction { + Instruction::Poseidon2(Box::new(Poseidon2Instr { + addrs: Poseidon2Io { + input: src.map(|r| r.read(self)), + output: dst.map(|r| r.write(self)), + }, + mults: [C::F::zero(); WIDTH], + })) + } + + fn exp_reverse_bits( + &mut self, + dst: impl Reg, + base: impl Reg, + exp: impl IntoIterator>, + ) -> Instruction { + Instruction::ExpReverseBitsLen(ExpReverseBitsInstr { + addrs: ExpReverseBitsIo { + result: dst.write(self), + base: base.read(self), + exp: exp.into_iter().map(|r| r.read(self)).collect(), + }, + mult: C::F::zero(), + }) + } + + fn hint_bit_decomposition( + &mut self, + value: impl Reg, + output: impl IntoIterator>, + ) -> Instruction { + Instruction::HintBits(HintBitsInstr { + output_addrs_mults: output.into_iter().map(|r| (r.write(self), C::F::zero())).collect(), + input_addr: value.read_ghost(self), + }) + } + + fn fri_fold( + &mut self, + CircuitV2FriFoldOutput { alpha_pow_output, ro_output }: CircuitV2FriFoldOutput, + CircuitV2FriFoldInput { + z, + alpha, + x, + mat_opening, + ps_at_z, + alpha_pow_input, + ro_input, + }: CircuitV2FriFoldInput, + ) -> Instruction { + Instruction::FriFold(Box::new(FriFoldInstr { + // Calculate before moving the vecs. + alpha_pow_mults: vec![C::F::zero(); alpha_pow_output.len()], + ro_mults: vec![C::F::zero(); ro_output.len()], + + base_single_addrs: FriFoldBaseIo { x: x.read(self) }, + ext_single_addrs: FriFoldExtSingleIo { z: z.read(self), alpha: alpha.read(self) }, + ext_vec_addrs: FriFoldExtVecIo { + mat_opening: mat_opening.into_iter().map(|e| e.read(self)).collect(), + ps_at_z: ps_at_z.into_iter().map(|e| e.read(self)).collect(), + alpha_pow_input: alpha_pow_input.into_iter().map(|e| e.read(self)).collect(), + ro_input: ro_input.into_iter().map(|e| e.read(self)).collect(), + alpha_pow_output: alpha_pow_output.into_iter().map(|e| e.write(self)).collect(), + ro_output: ro_output.into_iter().map(|e| e.write(self)).collect(), + }, + })) + } + + fn commit_public_values( + &mut self, + public_values: &RecursionPublicValues>, + ) -> Instruction { + public_values.digest.iter().for_each(|x| { + let _ = x.read(self); + }); + let pv_addrs = + unsafe { + transmute::< + RecursionPublicValues>, + [Felt; RECURSIVE_PROOF_NUM_PV_ELTS], + >(*public_values) + } + .map(|pv| pv.read_ghost(self)); + + let public_values_a: &RecursionPublicValues> = pv_addrs.as_slice().borrow(); + Instruction::CommitPublicValues(Box::new(CommitPublicValuesInstr { + pv_addrs: *public_values_a, + })) + } + + fn print_f(&mut self, addr: impl Reg) -> Instruction { + Instruction::Print(PrintInstr { + field_elt_type: FieldEltType::Base, + addr: addr.read_ghost(self), + }) + } + + fn print_e(&mut self, addr: impl Reg) -> Instruction { + Instruction::Print(PrintInstr { + field_elt_type: FieldEltType::Extension, + addr: addr.read_ghost(self), + }) + } + + fn ext2felts(&mut self, felts: [impl Reg; D], ext: impl Reg) -> Instruction { + Instruction::HintExt2Felts(HintExt2FeltsInstr { + output_addrs_mults: felts.map(|r| (r.write(self), C::F::zero())), + input_addr: ext.read_ghost(self), + }) + } + + fn hint(&mut self, output: &[impl Reg]) -> Instruction { + Instruction::Hint(HintInstr { + output_addrs_mults: output.iter().map(|r| (r.write(self), C::F::zero())).collect(), + }) + } + + /// Compiles one instruction, passing one or more instructions to `consumer`. + /// + /// We do not simply return a `Vec` for performance reasons --- results would be immediately fed + /// to `flat_map`, so we employ fusion/deforestation to eliminate intermediate data structures. + pub fn compile_one( + &mut self, + ir_instr: DslIr, + mut consumer: impl FnMut(Result, CompileOneErr>), + ) where + F: PrimeField + TwoAdicField, + C: Config + Debug, + { + // For readability. Avoids polluting outer scope. + use BaseAluOpcode::*; + use ExtAluOpcode::*; + + let mut f = |instr| consumer(Ok(instr)); + match ir_instr { + DslIr::ImmV(dst, src) => f(self.mem_write_const(dst, Imm::F(src))), + DslIr::ImmF(dst, src) => f(self.mem_write_const(dst, Imm::F(src))), + DslIr::ImmE(dst, src) => f(self.mem_write_const(dst, Imm::EF(src))), + + DslIr::AddV(dst, lhs, rhs) => f(self.base_alu(AddF, dst, lhs, rhs)), + DslIr::AddVI(dst, lhs, rhs) => f(self.base_alu(AddF, dst, lhs, Imm::F(rhs))), + DslIr::AddF(dst, lhs, rhs) => f(self.base_alu(AddF, dst, lhs, rhs)), + DslIr::AddFI(dst, lhs, rhs) => f(self.base_alu(AddF, dst, lhs, Imm::F(rhs))), + DslIr::AddE(dst, lhs, rhs) => f(self.ext_alu(AddE, dst, lhs, rhs)), + DslIr::AddEI(dst, lhs, rhs) => f(self.ext_alu(AddE, dst, lhs, Imm::EF(rhs))), + DslIr::AddEF(dst, lhs, rhs) => f(self.ext_alu(AddE, dst, lhs, rhs)), + DslIr::AddEFI(dst, lhs, rhs) => f(self.ext_alu(AddE, dst, lhs, Imm::F(rhs))), + DslIr::AddEFFI(dst, lhs, rhs) => f(self.ext_alu(AddE, dst, lhs, Imm::EF(rhs))), + + DslIr::SubV(dst, lhs, rhs) => f(self.base_alu(SubF, dst, lhs, rhs)), + DslIr::SubVI(dst, lhs, rhs) => f(self.base_alu(SubF, dst, lhs, Imm::F(rhs))), + DslIr::SubVIN(dst, lhs, rhs) => f(self.base_alu(SubF, dst, Imm::F(lhs), rhs)), + DslIr::SubF(dst, lhs, rhs) => f(self.base_alu(SubF, dst, lhs, rhs)), + DslIr::SubFI(dst, lhs, rhs) => f(self.base_alu(SubF, dst, lhs, Imm::F(rhs))), + DslIr::SubFIN(dst, lhs, rhs) => f(self.base_alu(SubF, dst, Imm::F(lhs), rhs)), + DslIr::SubE(dst, lhs, rhs) => f(self.ext_alu(SubE, dst, lhs, rhs)), + DslIr::SubEI(dst, lhs, rhs) => f(self.ext_alu(SubE, dst, lhs, Imm::EF(rhs))), + DslIr::SubEIN(dst, lhs, rhs) => f(self.ext_alu(SubE, dst, Imm::EF(lhs), rhs)), + DslIr::SubEFI(dst, lhs, rhs) => f(self.ext_alu(SubE, dst, lhs, Imm::F(rhs))), + DslIr::SubEF(dst, lhs, rhs) => f(self.ext_alu(SubE, dst, lhs, rhs)), + + DslIr::MulV(dst, lhs, rhs) => f(self.base_alu(MulF, dst, lhs, rhs)), + DslIr::MulVI(dst, lhs, rhs) => f(self.base_alu(MulF, dst, lhs, Imm::F(rhs))), + DslIr::MulF(dst, lhs, rhs) => f(self.base_alu(MulF, dst, lhs, rhs)), + DslIr::MulFI(dst, lhs, rhs) => f(self.base_alu(MulF, dst, lhs, Imm::F(rhs))), + DslIr::MulE(dst, lhs, rhs) => f(self.ext_alu(MulE, dst, lhs, rhs)), + DslIr::MulEI(dst, lhs, rhs) => f(self.ext_alu(MulE, dst, lhs, Imm::EF(rhs))), + DslIr::MulEFI(dst, lhs, rhs) => f(self.ext_alu(MulE, dst, lhs, Imm::F(rhs))), + DslIr::MulEF(dst, lhs, rhs) => f(self.ext_alu(MulE, dst, lhs, rhs)), + + DslIr::DivF(dst, lhs, rhs) => f(self.base_alu(DivF, dst, lhs, rhs)), + DslIr::DivFI(dst, lhs, rhs) => f(self.base_alu(DivF, dst, lhs, Imm::F(rhs))), + DslIr::DivFIN(dst, lhs, rhs) => f(self.base_alu(DivF, dst, Imm::F(lhs), rhs)), + DslIr::DivE(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, lhs, rhs)), + DslIr::DivEI(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, lhs, Imm::EF(rhs))), + DslIr::DivEIN(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, Imm::EF(lhs), rhs)), + DslIr::DivEFI(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, lhs, Imm::F(rhs))), + DslIr::DivEFIN(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, Imm::F(lhs), rhs)), + DslIr::DivEF(dst, lhs, rhs) => f(self.ext_alu(DivE, dst, lhs, rhs)), + + DslIr::NegV(dst, src) => f(self.base_alu(SubF, dst, Imm::F(C::F::zero()), src)), + DslIr::NegF(dst, src) => f(self.base_alu(SubF, dst, Imm::F(C::F::zero()), src)), + DslIr::NegE(dst, src) => f(self.ext_alu(SubE, dst, Imm::EF(C::EF::zero()), src)), + DslIr::InvV(dst, src) => f(self.base_alu(DivF, dst, Imm::F(C::F::one()), src)), + DslIr::InvF(dst, src) => f(self.base_alu(DivF, dst, Imm::F(C::F::one()), src)), + DslIr::InvE(dst, src) => f(self.ext_alu(DivE, dst, Imm::F(C::F::one()), src)), + + DslIr::AssertEqV(lhs, rhs) => self.base_assert_eq(lhs, rhs, f), + DslIr::AssertEqF(lhs, rhs) => self.base_assert_eq(lhs, rhs, f), + DslIr::AssertEqE(lhs, rhs) => self.ext_assert_eq(lhs, rhs, f), + DslIr::AssertEqVI(lhs, rhs) => self.base_assert_eq(lhs, Imm::F(rhs), f), + DslIr::AssertEqFI(lhs, rhs) => self.base_assert_eq(lhs, Imm::F(rhs), f), + DslIr::AssertEqEI(lhs, rhs) => self.ext_assert_eq(lhs, Imm::EF(rhs), f), + + DslIr::AssertNeV(lhs, rhs) => self.base_assert_ne(lhs, rhs, f), + DslIr::AssertNeF(lhs, rhs) => self.base_assert_ne(lhs, rhs, f), + DslIr::AssertNeE(lhs, rhs) => self.ext_assert_ne(lhs, rhs, f), + DslIr::AssertNeVI(lhs, rhs) => self.base_assert_ne(lhs, Imm::F(rhs), f), + DslIr::AssertNeFI(lhs, rhs) => self.base_assert_ne(lhs, Imm::F(rhs), f), + DslIr::AssertNeEI(lhs, rhs) => self.ext_assert_ne(lhs, Imm::EF(rhs), f), + + DslIr::CircuitV2Poseidon2PermuteBabyBear(data) => { + f(self.poseidon2_permute(data.0, data.1)) + } + DslIr::CircuitV2ExpReverseBits(dst, base, exp) => { + f(self.exp_reverse_bits(dst, base, exp)) + } + DslIr::CircuitV2HintBitsF(output, value) => { + f(self.hint_bit_decomposition(value, output)) + } + DslIr::CircuitV2FriFold(data) => f(self.fri_fold(data.0, data.1)), + DslIr::CircuitV2CommitPublicValues(public_values) => { + f(self.commit_public_values(&public_values)) + } + + DslIr::PrintV(dst) => f(self.print_f(dst)), + DslIr::PrintF(dst) => f(self.print_f(dst)), + DslIr::PrintE(dst) => f(self.print_e(dst)), + DslIr::CircuitV2HintFelts(output) => f(self.hint(&output)), + DslIr::CircuitV2HintExts(output) => f(self.hint(&output)), + DslIr::CircuitExt2Felt(felts, ext) => f(self.ext2felts(felts, ext)), + DslIr::CycleTrackerV2Enter(name) => { + consumer(Err(CompileOneErr::CycleTrackerEnter(name))) + } + DslIr::CycleTrackerV2Exit => consumer(Err(CompileOneErr::CycleTrackerExit)), + DslIr::ReduceE(_) => {} + instr => consumer(Err(CompileOneErr::Unsupported(instr))), + } + } + + /// Emit the instructions from a list of operations in the DSL. + pub fn compile(&mut self, operations: TracedVec>) -> RecursionProgram + where + F: PrimeField + TwoAdicField, + C: Config + Debug, + { + // In debug mode, we perform cycle tracking and keep track of backtraces. + // Otherwise, we ignore cycle tracking instructions and pass around an empty Vec of traces. + let debug_mode = sp1_debug_mode(); + // Compile each IR instruction into a list of ASM instructions, then combine them. + // This step also counts the number of times each address is read from. + let (mut instrs, traces) = tracing::debug_span!("compile_one loop").in_scope(|| { + let mut instrs = Vec::with_capacity(operations.vec.len()); + let mut traces = vec![]; + if debug_mode { + let mut span_builder = + SpanBuilder::<_, &'static str>::new("cycle_tracker".to_string()); + for (ir_instr, trace) in operations { + self.compile_one(ir_instr, &mut |item| match item { + Ok(instr) => { + span_builder.item(instr_name(&instr)); + instrs.push(instr); + traces.push(trace.clone()); + } + Err(CompileOneErr::CycleTrackerEnter(name)) => { + span_builder.enter(name); + } + Err(CompileOneErr::CycleTrackerExit) => { + span_builder.exit().unwrap(); + } + Err(CompileOneErr::Unsupported(instr)) => { + panic!("unsupported instruction: {instr:?}\nbacktrace: {:?}", trace) + } + }); + } + let cycle_tracker_root_span = span_builder.finish().unwrap(); + for line in cycle_tracker_root_span.lines() { + tracing::info!("{}", line); + } + } else { + for (ir_instr, trace) in operations { + self.compile_one(ir_instr, &mut |item| match item { + Ok(instr) => instrs.push(instr), + Err( + CompileOneErr::CycleTrackerEnter(_) | CompileOneErr::CycleTrackerExit, + ) => (), + Err(CompileOneErr::Unsupported(instr)) => { + panic!("unsupported instruction: {instr:?}\nbacktrace: {:?}", trace) + } + }); + } + } + (instrs, traces) + }); + + // Replace the mults using the address count data gathered in this previous. + // Exhaustive match for refactoring purposes. + let total_memory = self.addr_to_mult.len() + self.consts.len(); + let mut backfill = |(mult, addr): (&mut F, &Address)| { + *mult = self.addr_to_mult.remove(addr.as_usize()).unwrap() + }; + tracing::debug_span!("backfill mult").in_scope(|| { + for asm_instr in instrs.iter_mut() { + match asm_instr { + Instruction::BaseAlu(BaseAluInstr { + mult, + addrs: BaseAluIo { out: ref addr, .. }, + .. + }) => backfill((mult, addr)), + Instruction::ExtAlu(ExtAluInstr { + mult, + addrs: ExtAluIo { out: ref addr, .. }, + .. + }) => backfill((mult, addr)), + Instruction::Mem(MemInstr { + addrs: MemIo { inner: ref addr }, + mult, + kind: MemAccessKind::Write, + .. + }) => backfill((mult, addr)), + Instruction::Poseidon2(instr) => { + let Poseidon2SkinnyInstr { + addrs: Poseidon2Io { output: ref addrs, .. }, + mults, + } = instr.as_mut(); + mults.iter_mut().zip(addrs).for_each(&mut backfill); + } + Instruction::ExpReverseBitsLen(ExpReverseBitsInstr { + addrs: ExpReverseBitsIo { result: ref addr, .. }, + mult, + }) => backfill((mult, addr)), + Instruction::HintBits(HintBitsInstr { output_addrs_mults, .. }) + | Instruction::Hint(HintInstr { output_addrs_mults, .. }) => { + output_addrs_mults + .iter_mut() + .for_each(|(addr, mult)| backfill((mult, addr))); + } + Instruction::FriFold(instr) => { + let FriFoldInstr { + ext_vec_addrs: + FriFoldExtVecIo { ref alpha_pow_output, ref ro_output, .. }, + alpha_pow_mults, + ro_mults, + .. + } = instr.as_mut(); + // Using `.chain` seems to be less performant. + alpha_pow_mults.iter_mut().zip(alpha_pow_output).for_each(&mut backfill); + ro_mults.iter_mut().zip(ro_output).for_each(&mut backfill); + } + Instruction::HintExt2Felts(HintExt2FeltsInstr { + output_addrs_mults, .. + }) => { + output_addrs_mults + .iter_mut() + .for_each(|(addr, mult)| backfill((mult, addr))); + } + // Instructions that do not write to memory. + Instruction::Mem(MemInstr { kind: MemAccessKind::Read, .. }) + | Instruction::CommitPublicValues(_) + | Instruction::Print(_) => (), + } + } + }); + debug_assert!(self.addr_to_mult.is_empty()); + // Initialize constants. + let total_consts = self.consts.len(); + let instrs_consts = self.consts.drain().map(|(imm, (addr, mult))| { + Instruction::Mem(MemInstr { + addrs: MemIo { inner: addr }, + vals: MemIo { inner: imm.as_block() }, + mult, + kind: MemAccessKind::Write, + }) + }); + tracing::debug!("number of consts to initialize: {}", instrs_consts.len()); + // Reset the other fields. + self.next_addr = Default::default(); + self.virtual_to_physical.clear(); + // Place constant-initializing instructions at the top. + let (instructions, traces) = tracing::debug_span!("construct program").in_scope(|| { + if debug_mode { + let instrs_all = instrs_consts.chain(instrs); + let traces_all = repeat(None).take(total_consts).chain(traces); + (instrs_all.collect(), traces_all.collect()) + } else { + (instrs_consts.chain(instrs).collect(), traces) + } + }); + RecursionProgram { instructions, total_memory, traces } + } +} + +/// Used for cycle tracking. +const fn instr_name(instr: &Instruction) -> &'static str { + match instr { + Instruction::BaseAlu(_) => "BaseAlu", + Instruction::ExtAlu(_) => "ExtAlu", + Instruction::Mem(_) => "Mem", + Instruction::Poseidon2(_) => "Poseidon2", + Instruction::ExpReverseBitsLen(_) => "ExpReverseBitsLen", + Instruction::HintBits(_) => "HintBits", + Instruction::FriFold(_) => "FriFold", + Instruction::Print(_) => "Print", + Instruction::HintExt2Felts(_) => "HintExt2Felts", + Instruction::Hint(_) => "Hint", + Instruction::CommitPublicValues(_) => "CommitPublicValues", + } +} + +#[derive(Debug, Clone)] +pub enum CompileOneErr { + Unsupported(DslIr), + CycleTrackerEnter(String), + CycleTrackerExit, +} + +/// Immediate (i.e. constant) field element. +/// +/// Required to distinguish a base and extension field element at the type level, +/// since the IR's instructions do not provide this information. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Imm { + /// Element of the base field `F`. + F(F), + /// Element of the extension field `EF`. + EF(EF), +} + +impl Imm +where + F: AbstractField + Copy, + EF: AbstractExtensionField, +{ + // Get a `Block` of memory representing this immediate. + pub fn as_block(&self) -> Block { + match self { + Imm::F(f) => Block::from(*f), + Imm::EF(ef) => ef.as_base_slice().into(), + } + } +} + +/// Utility functions for various register types. +trait Reg { + /// Mark the register as to be read from, returning the "physical" address. + fn read(&self, compiler: &mut AsmCompiler) -> Address; + + /// Get the "physical" address of the register, assigning a new address if necessary. + fn read_ghost(&self, compiler: &mut AsmCompiler) -> Address; + + /// Mark the register as to be written to, returning the "physical" address. + fn write(&self, compiler: &mut AsmCompiler) -> Address; +} + +macro_rules! impl_reg_borrowed { + ($a:ty) => { + impl Reg for $a + where + C: Config, + T: Reg + ?Sized, + { + fn read(&self, compiler: &mut AsmCompiler) -> Address { + (**self).read(compiler) + } + + fn read_ghost(&self, compiler: &mut AsmCompiler) -> Address { + (**self).read_ghost(compiler) + } + + fn write(&self, compiler: &mut AsmCompiler) -> Address { + (**self).write(compiler) + } + } + }; +} + +// Allow for more flexibility in arguments. +impl_reg_borrowed!(&T); +impl_reg_borrowed!(&mut T); +impl_reg_borrowed!(Box); + +macro_rules! impl_reg_vaddr { + ($a:ty) => { + impl> Reg for $a { + fn read(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_vaddr(self.0 as usize) + } + fn read_ghost(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_ghost_vaddr(self.0 as usize) + } + fn write(&self, compiler: &mut AsmCompiler) -> Address { + compiler.write_fp(self.0 as usize) + } + } + }; +} + +// These three types have `.fp()` but they don't share a trait. +impl_reg_vaddr!(Var); +impl_reg_vaddr!(Felt); +impl_reg_vaddr!(Ext); + +impl> Reg for Imm { + fn read(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_const(*self) + } + + fn read_ghost(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_ghost_const(*self) + } + + fn write(&self, _compiler: &mut AsmCompiler) -> Address { + panic!("cannot write to immediate in register: {self:?}") + } +} + +impl> Reg for Address { + fn read(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_addr(*self); + *self + } + + fn read_ghost(&self, compiler: &mut AsmCompiler) -> Address { + compiler.read_ghost_addr(*self); + *self + } + + fn write(&self, compiler: &mut AsmCompiler) -> Address { + compiler.write_addr(*self); + *self + } +} + +#[cfg(test)] +mod tests { + use std::{collections::VecDeque, io::BufRead, iter::zip, sync::Arc}; + + use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_field::{Field, PrimeField32}; + use p3_symmetric::{CryptographicHasher, Permutation}; + use rand::{rngs::StdRng, Rng, SeedableRng}; + + use sp1_core_machine::utils::{run_test_machine, setup_logger}; + use sp1_recursion_core_v2::{machine::RecursionAir, RecursionProgram, Runtime}; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, inner_perm, BabyBearPoseidon2Inner, InnerHash, + StarkGenericConfig, + }; + + use crate::{ + asm::{AsmBuilder, AsmConfig}, + circuit::CircuitV2Builder, + }; + + use super::*; + + type SC = BabyBearPoseidon2; + type F = ::Val; + type EF = ::Challenge; + fn test_operations(operations: TracedVec>>) { + test_operations_with_runner(operations, |program| { + let mut runtime = Runtime::::new( + program, + BabyBearPoseidon2Inner::new().perm, + ); + runtime.run().unwrap(); + runtime.record + }); + } + + fn test_operations_with_runner( + operations: TracedVec>>, + run: impl FnOnce(Arc>) -> ExecutionRecord, + ) { + let mut compiler = super::AsmCompiler::>::default(); + let program = Arc::new(compiler.compile(operations)); + let record = run(program.clone()); + + // Run with the poseidon2 wide chip. + let wide_machine = RecursionAir::<_, 3, 0>::machine_wide(BabyBearPoseidon2::default()); + let (pk, vk) = wide_machine.setup(&program); + let result = run_test_machine(vec![record.clone()], wide_machine, pk, vk); + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + + // Run with the poseidon2 skinny chip. + let skinny_machine = RecursionAir::<_, 9, 0>::machine(BabyBearPoseidon2::compressed()); + let (pk, vk) = skinny_machine.setup(&program); + let result = run_test_machine(vec![record.clone()], skinny_machine, pk, vk); + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + } + + #[test] + fn test_poseidon2() { + setup_logger(); + + let mut builder = AsmBuilder::::default(); + let mut rng = StdRng::seed_from_u64(0xCAFEDA7E) + .sample_iter::<[F; WIDTH], _>(rand::distributions::Standard); + for _ in 0..100 { + let input_1: [F; WIDTH] = rng.next().unwrap(); + let output_1 = inner_perm().permute(input_1); + + let input_1_felts = input_1.map(|x| builder.eval(x)); + let output_1_felts = builder.poseidon2_permute_v2(input_1_felts); + let expected: [Felt<_>; WIDTH] = output_1.map(|x| builder.eval(x)); + for (lhs, rhs) in output_1_felts.into_iter().zip(expected) { + builder.assert_felt_eq(lhs, rhs); + } + } + + test_operations(builder.operations); + } + + #[test] + fn test_poseidon2_hash() { + let perm = inner_perm(); + let hasher = InnerHash::new(perm.clone()); + + let input: [F; 26] = [ + F::from_canonical_u32(0), + F::from_canonical_u32(1), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(2), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + F::from_canonical_u32(3), + ]; + let expected = hasher.hash_iter(input); + println!("{:?}", expected); + + let mut builder = AsmBuilder::::default(); + let input_felts: [Felt<_>; 26] = input.map(|x| builder.eval(x)); + let result = builder.poseidon2_hash_v2(&input_felts); + + for (actual_f, expected_f) in zip(result, expected) { + builder.assert_felt_eq(actual_f, expected_f); + } + } + + #[test] + fn test_exp_reverse_bits() { + setup_logger(); + + let mut builder = AsmBuilder::::default(); + let mut rng = + StdRng::seed_from_u64(0xEC0BEEF).sample_iter::(rand::distributions::Standard); + for _ in 0..100 { + let power_f = rng.next().unwrap(); + let power = power_f.as_canonical_u32(); + let power_bits = (0..NUM_BITS).map(|i| (power >> i) & 1).collect::>(); + + let input_felt = builder.eval(power_f); + let power_bits_felt = builder.num2bits_v2_f(input_felt, NUM_BITS); + + let base = rng.next().unwrap(); + let base_felt = builder.eval(base); + let result_felt = builder.exp_reverse_bits_v2(base_felt, power_bits_felt); + + let expected = power_bits + .into_iter() + .rev() + .zip(std::iter::successors(Some(base), |x| Some(x.square()))) + .map(|(bit, base_pow)| match bit { + 0 => F::one(), + 1 => base_pow, + _ => panic!("not a bit: {bit}"), + }) + .product::(); + let expected_felt: Felt<_> = builder.eval(expected); + builder.assert_felt_eq(result_felt, expected_felt); + } + test_operations(builder.operations); + } + + #[test] + fn test_fri_fold() { + setup_logger(); + + let mut builder = AsmBuilder::::default(); + + let mut rng = StdRng::seed_from_u64(0xFEB29).sample_iter(rand::distributions::Standard); + let mut random_felt = move || -> F { rng.next().unwrap() }; + let mut rng = + StdRng::seed_from_u64(0x0451).sample_iter::<[F; 4], _>(rand::distributions::Standard); + let mut random_ext = move || EF::from_base_slice(&rng.next().unwrap()); + + for i in 2..17 { + // Generate random values for the inputs. + let x = random_felt(); + let z = random_ext(); + let alpha = random_ext(); + + let alpha_pow_input = (0..i).map(|_| random_ext()).collect::>(); + let ro_input = (0..i).map(|_| random_ext()).collect::>(); + + let ps_at_z = (0..i).map(|_| random_ext()).collect::>(); + let mat_opening = (0..i).map(|_| random_ext()).collect::>(); + + // Compute the outputs from the inputs. + let alpha_pow_output = (0..i).map(|i| alpha_pow_input[i] * alpha).collect::>(); + let ro_output = (0..i) + .map(|i| { + ro_input[i] + alpha_pow_input[i] * (-ps_at_z[i] + mat_opening[i]) / (-z + x) + }) + .collect::>(); + + // Compute inputs and outputs through the builder. + let input_vars = CircuitV2FriFoldInput { + z: builder.eval(z.cons()), + alpha: builder.eval(alpha.cons()), + x: builder.eval(x), + mat_opening: mat_opening.iter().map(|e| builder.eval(e.cons())).collect(), + ps_at_z: ps_at_z.iter().map(|e| builder.eval(e.cons())).collect(), + alpha_pow_input: alpha_pow_input.iter().map(|e| builder.eval(e.cons())).collect(), + ro_input: ro_input.iter().map(|e| builder.eval(e.cons())).collect(), + }; + + let output_vars = builder.fri_fold_v2(input_vars); + for (lhs, rhs) in std::iter::zip(output_vars.alpha_pow_output, alpha_pow_output) { + builder.assert_ext_eq(lhs, rhs.cons()); + } + for (lhs, rhs) in std::iter::zip(output_vars.ro_output, ro_output) { + builder.assert_ext_eq(lhs, rhs.cons()); + } + } + + test_operations(builder.operations); + } + + #[test] + fn test_hint_bit_decomposition() { + setup_logger(); + + let mut builder = AsmBuilder::::default(); + let mut rng = + StdRng::seed_from_u64(0xC0FFEE7AB1E).sample_iter::(rand::distributions::Standard); + for _ in 0..100 { + let input_f = rng.next().unwrap(); + let input = input_f.as_canonical_u32(); + let output = (0..NUM_BITS).map(|i| (input >> i) & 1).collect::>(); + + let input_felt = builder.eval(input_f); + let output_felts = builder.num2bits_v2_f(input_felt, NUM_BITS); + let expected: Vec> = + output.into_iter().map(|x| builder.eval(F::from_canonical_u32(x))).collect(); + for (lhs, rhs) in output_felts.into_iter().zip(expected) { + builder.assert_felt_eq(lhs, rhs); + } + } + test_operations(builder.operations); + } + + #[test] + fn test_print_and_cycle_tracker() { + const ITERS: usize = 5; + + setup_logger(); + + let mut builder = AsmBuilder::::default(); + + let input_fs = StdRng::seed_from_u64(0xC0FFEE7AB1E) + .sample_iter::(rand::distributions::Standard) + .take(ITERS) + .collect::>(); + + let input_efs = StdRng::seed_from_u64(0x7EA7AB1E) + .sample_iter::<[F; 4], _>(rand::distributions::Standard) + .take(ITERS) + .collect::>(); + + let mut buf = VecDeque::::new(); + + builder.cycle_tracker_v2_enter("printing felts".to_string()); + for (i, &input_f) in input_fs.iter().enumerate() { + builder.cycle_tracker_v2_enter(format!("printing felt {i}")); + let input_felt = builder.eval(input_f); + builder.print_f(input_felt); + builder.cycle_tracker_v2_exit(); + } + builder.cycle_tracker_v2_exit(); + + builder.cycle_tracker_v2_enter("printing exts".to_string()); + for (i, input_block) in input_efs.iter().enumerate() { + builder.cycle_tracker_v2_enter(format!("printing ext {i}")); + let input_ext = builder.eval(EF::from_base_slice(input_block).cons()); + builder.print_e(input_ext); + builder.cycle_tracker_v2_exit(); + } + builder.cycle_tracker_v2_exit(); + + test_operations_with_runner(builder.operations, |program| { + let mut runtime = Runtime::::new( + program, + BabyBearPoseidon2Inner::new().perm, + ); + runtime.debug_stdout = Box::new(&mut buf); + runtime.run().unwrap(); + runtime.record + }); + + let input_str_fs = input_fs.into_iter().map(|elt| format!("{}", elt)); + let input_str_efs = input_efs.into_iter().map(|elt| format!("{:?}", elt)); + let input_strs = input_str_fs.chain(input_str_efs); + + for (input_str, line) in zip(input_strs, buf.lines()) { + let line = line.unwrap(); + assert!(line.contains(&input_str)); + } + } + + #[test] + fn test_ext2felts() { + setup_logger(); + + let mut builder = AsmBuilder::::default(); + let mut rng = + StdRng::seed_from_u64(0x3264).sample_iter::<[F; 4], _>(rand::distributions::Standard); + let mut random_ext = move || EF::from_base_slice(&rng.next().unwrap()); + for _ in 0..100 { + let input = random_ext(); + let output: &[F] = input.as_base_slice(); + + let input_ext = builder.eval(input.cons()); + let output_felts = builder.ext2felt_v2(input_ext); + let expected: Vec> = output.iter().map(|&x| builder.eval(x)).collect(); + for (lhs, rhs) in output_felts.into_iter().zip(expected) { + builder.assert_felt_eq(lhs, rhs); + } + } + test_operations(builder.operations); + } + + macro_rules! test_assert_fixture { + ($assert_felt:ident, $assert_ext:ident, $should_offset:literal) => { + { + use std::convert::identity; + let mut builder = AsmBuilder::::default(); + test_assert_fixture!(builder, identity, F, Felt<_>, 0xDEADBEEF, $assert_felt, $should_offset); + test_assert_fixture!(builder, EF::cons, EF, Ext<_, _>, 0xABADCAFE, $assert_ext, $should_offset); + test_operations(builder.operations); + } + }; + ($builder:ident, $wrap:path, $t:ty, $u:ty, $seed:expr, $assert:ident, $should_offset:expr) => { + { + let mut elts = StdRng::seed_from_u64($seed) + .sample_iter::<$t, _>(rand::distributions::Standard); + for _ in 0..100 { + let a = elts.next().unwrap(); + let b = elts.next().unwrap(); + let c = a + b; + let ar: $u = $builder.eval($wrap(a)); + let br: $u = $builder.eval($wrap(b)); + let cr: $u = $builder.eval(ar + br); + let cm = if $should_offset { + c + elts.find(|x| !x.is_zero()).unwrap() + } else { + c + }; + $builder.$assert(cr, $wrap(cm)); + } + } + }; + } + + #[test] + fn test_assert_eq_noop() { + test_assert_fixture!(assert_felt_eq, assert_ext_eq, false); + } + + #[test] + #[should_panic] + fn test_assert_eq_panics() { + test_assert_fixture!(assert_felt_eq, assert_ext_eq, true); + } + + #[test] + fn test_assert_ne_noop() { + test_assert_fixture!(assert_felt_ne, assert_ext_ne, true); + } + + #[test] + #[should_panic] + fn test_assert_ne_panics() { + test_assert_fixture!(assert_felt_ne, assert_ext_ne, false); + } +} diff --git a/crates/recursion/compiler/src/circuit/mod.rs b/crates/recursion/compiler/src/circuit/mod.rs new file mode 100644 index 0000000000..1fbe681c70 --- /dev/null +++ b/crates/recursion/compiler/src/circuit/mod.rs @@ -0,0 +1,203 @@ +mod builder; +mod compiler; + +pub use builder::*; +pub use compiler::*; + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_field::{AbstractExtensionField, AbstractField}; + use rand::{rngs::StdRng, Rng, SeedableRng}; + + use sp1_core_machine::utils::{run_test_machine, setup_logger}; + use sp1_recursion_core_v2::{ + chips::{ + alu_base::BaseAluChip, + alu_ext::ExtAluChip, + exp_reverse_bits::ExpReverseBitsLenChip, + fri_fold::FriFoldChip, + mem::{MemoryConstChip, MemoryVarChip}, + poseidon2_wide::Poseidon2WideChip, + }, + machine::RecursionAir, + Runtime, RuntimeError, + }; + use sp1_stark::{ + BabyBearPoseidon2Inner, Chip, StarkGenericConfig, StarkMachine, PROOF_MAX_NUM_PVS, + }; + + use crate::{ + asm::AsmBuilder, + circuit::{AsmCompiler, CircuitV2Builder}, + ir::*, + }; + + const DEGREE: usize = 3; + + type SC = BabyBearPoseidon2Inner; + type F = ::Val; + type EF = ::Challenge; + type A = RecursionAir; + + /// Rough test to give an idea of how long the compress stage would take on the v2 circuit + /// relative to the recursion VM. + /// + /// The constants below were manually populated by running + /// `RUST_LOG=debug RUST_LOGGER=forest FRI_QUERIES=100 cargo test + /// --release --package sp1-prover -- --exact tests::test_e2e` + /// and writing down numbers from the first `prove_shards` section of the compress stage. + /// We use those numbers to create a dummy circuit that should roughly be the size of + /// the finished circuit, which will be equivalent to the compress program on the VM. + /// Therefore, by running `RUST_LOG=debug RUST_LOGGER=forest FRI_QUERIES=100 cargo test + /// -release --lib --features native-gnark -- test_compress_dummy_circuit` + /// and comparing the durations of the `prove_shards` sections, we can roughly estimate the + /// speed-up factor. At the time of writing, the factor is approximately 30.4s/3.5s = 8.7. + #[test] + fn test_compress_dummy_circuit() { + setup_logger(); + + // To aid in testing. + const SCALE: usize = 1; + const FIELD_OPERATIONS: usize = 451653 * SCALE; + const EXTENSION_OPERATIONS: usize = 82903 * SCALE; + const POSEIDON_OPERATIONS: usize = 34697 * SCALE; + const EXP_REVERSE_BITS_LEN_OPERATIONS: usize = 35200 * SCALE; + const FRI_FOLD_OPERATIONS: usize = 152800 * SCALE; + + let mut builder = AsmBuilder::::default(); + + let mut rng = StdRng::seed_from_u64(0xFEB29).sample_iter(rand::distributions::Standard); + let mut random_felt = move || -> F { rng.next().unwrap() }; + let mut rng = + StdRng::seed_from_u64(0x0451).sample_iter::<[F; 4], _>(rand::distributions::Standard); + let mut random_ext = move || EF::from_base_slice(&rng.next().unwrap()); + + for _ in 0..FIELD_OPERATIONS { + let a: Felt<_> = builder.eval(random_felt()); + let b: Felt<_> = builder.eval(random_felt()); + let _: Felt<_> = builder.eval(a + b); + } + for _ in 0..EXTENSION_OPERATIONS { + let a: Ext<_, _> = builder.eval(random_ext().cons()); + let b: Ext<_, _> = builder.eval(random_ext().cons()); + let _: Ext<_, _> = builder.eval(a + b); + } + + let operations = builder.operations; + let mut compiler = AsmCompiler::default(); + let program = Arc::new(compiler.compile(operations)); + let mut runtime = Runtime::::new( + program.clone(), + BabyBearPoseidon2Inner::new().perm, + ); + runtime.run().unwrap(); + + // Construct the machine ourselves so we can pad the tables, avoiding `A::machine`. + let config = SC::default(); + let chips: Vec> = vec![ + A::MemoryConst(MemoryConstChip::default()), + A::MemoryVar(MemoryVarChip::default()), + A::BaseAlu(BaseAluChip::default()), + A::ExtAlu(ExtAluChip::default()), + A::Poseidon2Wide(Poseidon2WideChip:: { + fixed_log2_rows: Some(((POSEIDON_OPERATIONS - 1).ilog2() + 1) as usize), + pad: true, + }), + A::ExpReverseBitsLen(ExpReverseBitsLenChip:: { + fixed_log2_rows: Some(((EXP_REVERSE_BITS_LEN_OPERATIONS - 1).ilog2() + 1) as usize), + pad: true, + }), + A::FriFold(FriFoldChip:: { + fixed_log2_rows: Some(((FRI_FOLD_OPERATIONS - 1).ilog2() + 1) as usize), + pad: true, + }), + ] + .into_iter() + .map(Chip::new) + .collect(); + let machine = StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS); + + let (pk, vk) = machine.setup(&program); + let result = + run_test_machine(vec![runtime.record], machine, pk, vk.clone()).expect("should verify"); + + tracing::info!("num shard proofs: {}", result.shard_proofs.len()); + } + + #[test] + fn test_io() { + let mut builder = AsmBuilder::::default(); + + let felts = builder.hint_felts_v2(3); + assert_eq!(felts.len(), 3); + let sum: Felt<_> = builder.eval(felts[0] + felts[1]); + builder.assert_felt_eq(sum, felts[2]); + + let exts = builder.hint_exts_v2(3); + assert_eq!(exts.len(), 3); + let sum: Ext<_, _> = builder.eval(exts[0] + exts[1]); + builder.assert_ext_ne(sum, exts[2]); + + let x = builder.hint_ext_v2(); + builder.assert_ext_eq(x, exts[0] + felts[0]); + + let y = builder.hint_felt_v2(); + let zero: Felt<_> = builder.constant(F::zero()); + builder.assert_felt_eq(y, zero); + + let operations = builder.operations; + let mut compiler = AsmCompiler::default(); + let program = Arc::new(compiler.compile(operations)); + let mut runtime = + Runtime::::new(program.clone(), SC::new().perm); + runtime.witness_stream = [ + vec![F::one().into(), F::one().into(), F::two().into()], + vec![F::zero().into(), F::one().into(), F::two().into()], + vec![F::one().into()], + vec![F::zero().into()], + ] + .concat() + .into(); + runtime.run().unwrap(); + + let machine = A::machine_wide(SC::new()); + + let (pk, vk) = machine.setup(&program); + let result = + run_test_machine(vec![runtime.record], machine, pk, vk.clone()).expect("should verify"); + + tracing::info!("num shard proofs: {}", result.shard_proofs.len()); + } + + #[test] + fn test_empty_witness_stream() { + let mut builder = AsmBuilder::::default(); + + let felts = builder.hint_felts_v2(3); + assert_eq!(felts.len(), 3); + let sum: Felt<_> = builder.eval(felts[0] + felts[1]); + builder.assert_felt_eq(sum, felts[2]); + + let exts = builder.hint_exts_v2(3); + assert_eq!(exts.len(), 3); + let sum: Ext<_, _> = builder.eval(exts[0] + exts[1]); + builder.assert_ext_ne(sum, exts[2]); + + let operations = builder.operations; + let mut compiler = AsmCompiler::default(); + let program = Arc::new(compiler.compile(operations)); + let mut runtime = + Runtime::::new(program.clone(), SC::new().perm); + runtime.witness_stream = + [vec![F::one().into(), F::one().into(), F::two().into()]].concat().into(); + + match runtime.run() { + Err(RuntimeError::EmptyWitnessStream) => (), + Ok(_) => panic!("should not succeed"), + Err(x) => panic!("should not yield error variant: {}", x), + } + } +} diff --git a/recursion/compiler/src/config.rs b/crates/recursion/compiler/src/config.rs similarity index 89% rename from recursion/compiler/src/config.rs rename to crates/recursion/compiler/src/config.rs index d432a0fe7e..2beec186b8 100644 --- a/recursion/compiler/src/config.rs +++ b/crates/recursion/compiler/src/config.rs @@ -1,7 +1,7 @@ use p3_baby_bear::BabyBear; use p3_bn254_fr::Bn254Fr; use p3_field::extension::BinomialExtensionField; -use sp1_core::utils::{InnerChallenge, InnerVal}; +use sp1_stark::{InnerChallenge, InnerVal}; use crate::{asm::AsmConfig, prelude::Config}; diff --git a/recursion/compiler/src/constraints/mod.rs b/crates/recursion/compiler/src/constraints/mod.rs similarity index 91% rename from recursion/compiler/src/constraints/mod.rs rename to crates/recursion/compiler/src/constraints/mod.rs index 612aee4a46..58a0fff3cb 100644 --- a/recursion/compiler/src/constraints/mod.rs +++ b/crates/recursion/compiler/src/constraints/mod.rs @@ -1,16 +1,15 @@ pub mod opcodes; use core::fmt::Debug; -use p3_field::AbstractExtensionField; -use p3_field::Field; -use p3_field::PrimeField; +use p3_field::{AbstractExtensionField, Field, PrimeField}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; use self::opcodes::ConstraintOpcode; -use crate::ir::Config; -use crate::ir::DslIr; -use crate::prelude::TracedVec; +use crate::{ + ir::{Config, DslIr}, + prelude::TracedVec, +}; /// A constraint is an operation and a list of nested arguments. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -39,10 +38,7 @@ impl ConstraintCompiler { let tmp_id = self.alloc_id(); constraints.push(Constraint { opcode: ConstraintOpcode::ImmV, - args: vec![ - vec![tmp_id.clone()], - vec![value.as_canonical_biguint().to_string()], - ], + args: vec![vec![tmp_id.clone()], vec![value.as_canonical_biguint().to_string()]], }); tmp_id } @@ -52,10 +48,7 @@ impl ConstraintCompiler { let tmp_id = self.alloc_id(); constraints.push(Constraint { opcode: ConstraintOpcode::ImmF, - args: vec![ - vec![tmp_id.clone()], - vec![value.as_canonical_biguint().to_string()], - ], + args: vec![vec![tmp_id.clone()], vec![value.as_canonical_biguint().to_string()]], }); tmp_id } @@ -159,6 +152,13 @@ impl ConstraintCompiler { opcode: ConstraintOpcode::SubF, args: vec![vec![a.id()], vec![b.id()], vec![c.id()]], }), + DslIr::SubFI(a, b, c) => { + let tmp = self.alloc_f(&mut constraints, c); + constraints.push(Constraint { + opcode: ConstraintOpcode::SubF, + args: vec![vec![a.id()], vec![b.id()], vec![tmp]], + }); + } DslIr::SubE(a, b, c) => constraints.push(Constraint { opcode: ConstraintOpcode::SubE, args: vec![vec![a.id()], vec![b.id()], vec![c.id()]], @@ -196,6 +196,13 @@ impl ConstraintCompiler { opcode: ConstraintOpcode::MulF, args: vec![vec![a.id()], vec![b.id()], vec![c.id()]], }), + DslIr::MulFI(a, b, c) => { + let tmp = self.alloc_f(&mut constraints, c); + constraints.push(Constraint { + opcode: ConstraintOpcode::MulF, + args: vec![vec![a.id()], vec![b.id()], vec![tmp]], + }); + } DslIr::MulE(a, b, c) => constraints.push(Constraint { opcode: ConstraintOpcode::MulE, args: vec![vec![a.id()], vec![b.id()], vec![c.id()]], @@ -214,7 +221,7 @@ impl ConstraintCompiler { DslIr::DivFIN(a, b, c) => { let tmp = self.alloc_f(&mut constraints, b.inverse()); constraints.push(Constraint { - opcode: ConstraintOpcode::MulF, + opcode: ConstraintOpcode::DivF, args: vec![vec![a.id()], vec![tmp], vec![c.id()]], }); } @@ -358,10 +365,22 @@ impl ConstraintCompiler { vec![a[3].id()], ], }), + // Ignore cycle tracker instruction. + // It currently serves as a marker for calculation at compile time. + DslIr::CycleTracker(_) => (), + DslIr::CycleTrackerV2Enter(_) => (), + DslIr::CycleTrackerV2Exit => (), DslIr::ReduceE(a) => constraints.push(Constraint { opcode: ConstraintOpcode::ReduceE, args: vec![vec![a.id()]], }), + DslIr::CircuitFelt2Var(a, b) => constraints.push(Constraint { + opcode: ConstraintOpcode::CircuitFelt2Var, + args: vec![vec![b.id()], vec![a.id()]], + }), + + // Version 2 instructions + DslIr::CircuitV2CommitPublicValues(_) => {} _ => panic!("unsupported {:?}", instruction), }; } diff --git a/recursion/compiler/src/constraints/opcodes.rs b/crates/recursion/compiler/src/constraints/opcodes.rs similarity index 97% rename from recursion/compiler/src/constraints/opcodes.rs rename to crates/recursion/compiler/src/constraints/opcodes.rs index 02ed47eea5..edb6b1c2e0 100644 --- a/recursion/compiler/src/constraints/opcodes.rs +++ b/crates/recursion/compiler/src/constraints/opcodes.rs @@ -46,6 +46,7 @@ pub enum ConstraintOpcode { CommitVkeyHash, CommitCommitedValuesDigest, CircuitFelts2Ext, + CircuitFelt2Var, PermuteBabyBear, ReduceE, } diff --git a/recursion/compiler/src/ir/bits.rs b/crates/recursion/compiler/src/ir/bits.rs similarity index 97% rename from recursion/compiler/src/ir/bits.rs rename to crates/recursion/compiler/src/ir/bits.rs index b08a7e29e5..25cf97c05f 100644 --- a/recursion/compiler/src/ir/bits.rs +++ b/crates/recursion/compiler/src/ir/bits.rs @@ -179,8 +179,8 @@ impl Builder { /// SAFETY: This function assumes that the num_bits values are already verified to be boolean. /// /// The babybear modulus in LE bits is: 100_000_000_000_000_000_000_000_000_111_1. - /// To check that the num_bits array is less than that value, we first check if the most significant - /// bits are all 1. If it is, then we assert that the other bits are all 0. + /// To check that the num_bits array is less than that value, we first check if the most + /// significant bits are all 1. If it is, then we assert that the other bits are all 0. fn less_than_bb_modulus(&mut self, num_bits: Array>) { let one: Var<_> = self.eval(C::N::one()); let zero: Var<_> = self.eval(C::N::zero()); @@ -197,7 +197,8 @@ impl Builder { sum_least_sig_bits = self.eval(bit + sum_least_sig_bits); } - // If the most significant 4 bits are all 1, then check the sum of the least significant bits, else return zero. + // If the most significant 4 bits are all 1, then check the sum of the least significant + // bits, else return zero. let check: Var<_> = self.eval(most_sig_4_bits * sum_least_sig_bits + (one - most_sig_4_bits) * zero); self.assert_var_eq(check, zero); diff --git a/recursion/compiler/src/ir/builder.rs b/crates/recursion/compiler/src/ir/builder.rs similarity index 85% rename from recursion/compiler/src/ir/builder.rs rename to crates/recursion/compiler/src/ir/builder.rs index f9236b8970..19cd92b6e9 100644 --- a/recursion/compiler/src/ir/builder.rs +++ b/crates/recursion/compiler/src/ir/builder.rs @@ -2,6 +2,7 @@ use std::{iter::Zip, vec::IntoIter}; use backtrace::Backtrace; use p3_field::AbstractField; +use sp1_core_machine::utils::sp1_debug_mode; use sp1_primitives::types::RecursionProgramType; use super::{ @@ -26,19 +27,13 @@ impl Default for TracedVec { impl From> for TracedVec { fn from(vec: Vec) -> Self { let len = vec.len(); - Self { - vec, - traces: vec![None; len], - } + Self { vec, traces: vec![None; len] } } } impl TracedVec { pub const fn new() -> Self { - Self { - vec: Vec::new(), - traces: Vec::new(), - } + Self { vec: Vec::new(), traces: Vec::new() } } pub fn push(&mut self, value: T) { @@ -49,18 +44,11 @@ impl TracedVec { /// Pushes a value to the vector and records a backtrace if SP1_DEBUG is enabled pub fn trace_push(&mut self, value: T) { self.vec.push(value); - match std::env::var("SP1_DEBUG") - .unwrap_or("false".to_string()) - .to_lowercase() - .as_str() - { - "true" => { - self.traces.push(Some(Backtrace::new_unresolved())); - } - _ => { - self.traces.push(None); - } - }; + if sp1_debug_mode() { + self.traces.push(Some(Backtrace::new_unresolved())); + } else { + self.traces.push(None); + } } pub fn extend)>>(&mut self, iter: I) { @@ -93,9 +81,7 @@ impl IntoIterator for TracedVec { /// Can compile to both assembly and a set of constraints. #[derive(Debug, Clone)] pub struct Builder { - pub(crate) felt_count: u32, - pub(crate) ext_count: u32, - pub(crate) var_count: u32, + pub(crate) variable_count: u32, pub operations: TracedVec>, pub(crate) nb_public_values: Option>, pub(crate) witness_var_count: u32, @@ -119,9 +105,7 @@ impl Builder { let placeholder_p2_hash_num = Var::new(0); let mut new_builder = Self { - felt_count: 0, - ext_count: 0, - var_count: 0, + variable_count: 0, witness_var_count: 0, witness_felt_count: 0, witness_ext_count: 0, @@ -139,20 +123,17 @@ impl Builder { /// Creates a new builder with a given number of counts for each type. pub fn new_sub_builder( - var_count: u32, - felt_count: u32, - ext_count: u32, + variable_count: u32, nb_public_values: Option>, p2_hash_num: Var, debug: bool, program_type: RecursionProgramType, ) -> Self { Self { - felt_count, - ext_count, - var_count, - // Witness counts are only used when the target is a gnark circuit. And sub-builders are - // not used when the target is a gnark circuit, so it's fine to set the witness counts to 0. + variable_count, + // Witness counts are only used when the target is a gnark circuit. And sub-builders + // are not used when the target is a gnark circuit, so it's fine to set the + // witness counts to 0. witness_var_count: 0, witness_felt_count: 0, witness_ext_count: 0, @@ -308,12 +289,7 @@ impl Builder { lhs: LhsExpr, rhs: RhsExpr, ) -> IfBuilder { - IfBuilder { - lhs: lhs.into(), - rhs: rhs.into(), - is_eq: true, - builder: self, - } + IfBuilder { lhs: lhs.into(), rhs: rhs.into(), is_eq: true, builder: self } } /// Evaluate a block of operations if two expressions are not equal. @@ -322,12 +298,7 @@ impl Builder { lhs: LhsExpr, rhs: RhsExpr, ) -> IfBuilder { - IfBuilder { - lhs: lhs.into(), - rhs: rhs.into(), - is_eq: false, - builder: self, - } + IfBuilder { lhs: lhs.into(), rhs: rhs.into(), is_eq: false, builder: self } } /// Evaluate a block of operations over a range from start to end. @@ -336,12 +307,7 @@ impl Builder { start: impl Into>, end: impl Into>, ) -> RangeBuilder { - RangeBuilder { - start: start.into(), - end: end.into(), - builder: self, - step_size: 1, - } + RangeBuilder { start: start.into(), end: end.into(), builder: self, step_size: 1 } } /// Break out of a loop. @@ -425,37 +391,25 @@ impl Builder { } pub fn witness_var(&mut self) -> Var { - assert!( - !self.is_sub_builder, - "Cannot create a witness var with a sub builder" - ); + assert!(!self.is_sub_builder, "Cannot create a witness var with a sub builder"); let witness = self.uninit(); - self.operations - .push(DslIr::WitnessVar(witness, self.witness_var_count)); + self.operations.push(DslIr::WitnessVar(witness, self.witness_var_count)); self.witness_var_count += 1; witness } pub fn witness_felt(&mut self) -> Felt { - assert!( - !self.is_sub_builder, - "Cannot create a witness felt with a sub builder" - ); + assert!(!self.is_sub_builder, "Cannot create a witness felt with a sub builder"); let witness = self.uninit(); - self.operations - .push(DslIr::WitnessFelt(witness, self.witness_felt_count)); + self.operations.push(DslIr::WitnessFelt(witness, self.witness_felt_count)); self.witness_felt_count += 1; witness } pub fn witness_ext(&mut self) -> Ext { - assert!( - !self.is_sub_builder, - "Cannot create a witness ext with a sub builder" - ); + assert!(!self.is_sub_builder, "Cannot create a witness ext with a sub builder"); let witness = self.uninit(); - self.operations - .push(DslIr::WitnessExt(witness, self.witness_ext_count)); + self.operations.push(DslIr::WitnessExt(witness, self.witness_ext_count)); self.witness_ext_count += 1; witness } @@ -480,10 +434,7 @@ impl Builder { /// Register and commits a felt as public value. This value will be constrained when verified. pub fn commit_public_value(&mut self, val: Felt) { - assert!( - !self.is_sub_builder, - "Cannot commit to a public value with a sub builder" - ); + assert!(!self.is_sub_builder, "Cannot commit to a public value with a sub builder"); if self.nb_public_values.is_none() { self.nb_public_values = Some(self.eval(C::N::zero())); } @@ -495,10 +446,7 @@ impl Builder { /// Commits an array of felts in public values. pub fn commit_public_values(&mut self, vals: &Array>) { - assert!( - !self.is_sub_builder, - "Cannot commit to public values with a sub builder" - ); + assert!(!self.is_sub_builder, "Cannot commit to public values with a sub builder"); let len = vals.len(); self.range(0, len).for_each(|i, builder| { let val = builder.get(vals, i); @@ -511,14 +459,19 @@ impl Builder { } pub fn commit_commited_values_digest_circuit(&mut self, var: Var) { - self.operations - .push(DslIr::CircuitCommitCommitedValuesDigest(var)); + self.operations.push(DslIr::CircuitCommitCommitedValuesDigest(var)); } pub fn reduce_e(&mut self, ext: Ext) { self.operations.push(DslIr::ReduceE(ext)); } + pub fn felt2var_circuit(&mut self, felt: Felt) -> Var { + let var = self.uninit(); + self.operations.push(DslIr::CircuitFelt2Var(felt, var)); + var + } + pub fn cycle_tracker(&mut self, name: &str) { self.operations.push(DslIr::CycleTracker(name.to_string())); } @@ -553,9 +506,7 @@ impl<'a, C: Config> IfBuilder<'a, C> { // Execute the `then` block and collect the instructions. let mut f_builder = Builder::::new_sub_builder( - self.builder.var_count, - self.builder.felt_count, - self.builder.ext_count, + self.builder.variable_count, self.builder.nb_public_values, self.builder.p2_hash_num, self.builder.debug, @@ -579,19 +530,19 @@ impl<'a, C: Config> IfBuilder<'a, C> { } } IfCondition::Eq(lhs, rhs) => { - let op = DslIr::IfEq(lhs, rhs, then_instructions, Default::default()); + let op = DslIr::IfEq(Box::new((lhs, rhs, then_instructions, Default::default()))); self.builder.operations.push(op); } IfCondition::EqI(lhs, rhs) => { - let op = DslIr::IfEqI(lhs, rhs, then_instructions, Default::default()); + let op = DslIr::IfEqI(Box::new((lhs, rhs, then_instructions, Default::default()))); self.builder.operations.push(op); } IfCondition::Ne(lhs, rhs) => { - let op = DslIr::IfNe(lhs, rhs, then_instructions, Default::default()); + let op = DslIr::IfNe(Box::new((lhs, rhs, then_instructions, Default::default()))); self.builder.operations.push(op); } IfCondition::NeI(lhs, rhs) => { - let op = DslIr::IfNeI(lhs, rhs, then_instructions, Default::default()); + let op = DslIr::IfNeI(Box::new((lhs, rhs, then_instructions, Default::default()))); self.builder.operations.push(op); } } @@ -605,9 +556,7 @@ impl<'a, C: Config> IfBuilder<'a, C> { // Get the condition reduced from the expressions for lhs and rhs. let condition = self.condition(); let mut then_builder = Builder::::new_sub_builder( - self.builder.var_count, - self.builder.felt_count, - self.builder.ext_count, + self.builder.variable_count, self.builder.nb_public_values, self.builder.p2_hash_num, self.builder.debug, @@ -621,9 +570,7 @@ impl<'a, C: Config> IfBuilder<'a, C> { let then_instructions = then_builder.operations; let mut else_builder = Builder::::new_sub_builder( - self.builder.var_count, - self.builder.felt_count, - self.builder.ext_count, + self.builder.variable_count, self.builder.nb_public_values, self.builder.p2_hash_num, self.builder.debug, @@ -651,19 +598,19 @@ impl<'a, C: Config> IfBuilder<'a, C> { } } IfCondition::Eq(lhs, rhs) => { - let op = DslIr::IfEq(lhs, rhs, then_instructions, else_instructions); + let op = DslIr::IfEq(Box::new((lhs, rhs, then_instructions, else_instructions))); self.builder.operations.push(op); } IfCondition::EqI(lhs, rhs) => { - let op = DslIr::IfEqI(lhs, rhs, then_instructions, else_instructions); + let op = DslIr::IfEqI(Box::new((lhs, rhs, then_instructions, else_instructions))); self.builder.operations.push(op); } IfCondition::Ne(lhs, rhs) => { - let op = DslIr::IfNe(lhs, rhs, then_instructions, else_instructions); + let op = DslIr::IfNe(Box::new((lhs, rhs, then_instructions, else_instructions))); self.builder.operations.push(op); } IfCondition::NeI(lhs, rhs) => { - let op = DslIr::IfNeI(lhs, rhs, then_instructions, else_instructions); + let op = DslIr::IfNeI(Box::new((lhs, rhs, then_instructions, else_instructions))); self.builder.operations.push(op); } } @@ -759,9 +706,7 @@ impl<'a, C: Config> RangeBuilder<'a, C> { let step_size = C::N::from_canonical_usize(self.step_size); let loop_variable: Var = self.builder.uninit(); let mut loop_body_builder = Builder::::new_sub_builder( - self.builder.var_count, - self.builder.felt_count, - self.builder.ext_count, + self.builder.variable_count, self.builder.nb_public_values, self.builder.p2_hash_num, self.builder.debug, @@ -773,13 +718,13 @@ impl<'a, C: Config> RangeBuilder<'a, C> { let loop_instructions = loop_body_builder.operations; - let op = DslIr::For( + let op = DslIr::For(Box::new(( self.start, self.end, step_size, loop_variable, loop_instructions, - ); + ))); self.builder.operations.push(op); } } diff --git a/recursion/compiler/src/ir/collections.rs b/crates/recursion/compiler/src/ir/collections.rs similarity index 92% rename from recursion/compiler/src/ir/collections.rs rename to crates/recursion/compiler/src/ir/collections.rs index e32400f656..92f6cf96b6 100644 --- a/recursion/compiler/src/ir/collections.rs +++ b/crates/recursion/compiler/src/ir/collections.rs @@ -36,9 +36,7 @@ impl> Array { Self::Dyn(ptr, len) => { assert!(V::size_of() == 1, "only support variables of size 1"); let new_address = builder.eval(ptr.address + shift); - let new_ptr = Ptr:: { - address: new_address, - }; + let new_ptr = Ptr:: { address: new_address }; let len_var = len.materialize(builder); let new_length = builder.eval(len_var - shift); Array::Dyn(new_ptr, Usize::Var(new_length)) @@ -143,11 +141,7 @@ impl Builder { let valid = self.lt(index_v, len_v); self.assert_var_eq(valid, C::N::one()); } - let index = MemIndex { - index, - offset: 0, - size: V::size_of(), - }; + let index = MemIndex { index, offset: 0, size: V::size_of() }; let var: V = self.uninit(); self.load(var.clone(), *ptr, index); var @@ -173,11 +167,7 @@ impl Builder { let valid = self.lt(index_v, len_v); self.assert_var_eq(valid, C::N::one()); } - let index = MemIndex { - index, - offset: 0, - size: V::size_of(), - }; + let index = MemIndex { index, offset: 0, size: V::size_of() }; let var: Ptr = self.uninit(); self.load(var, *ptr, index); var @@ -204,11 +194,7 @@ impl Builder { let valid = self.lt(index_v, len_v); self.assert_var_eq(valid, C::N::one()); } - let index = MemIndex { - index, - offset: 0, - size: V::size_of(), - }; + let index = MemIndex { index, offset: 0, size: V::size_of() }; let value: V = self.eval(value); self.store(*ptr, index, value); } @@ -228,11 +214,7 @@ impl Builder { todo!() } Array::Dyn(ptr, _) => { - let index = MemIndex { - index, - offset: 0, - size: V::size_of(), - }; + let index = MemIndex { index, offset: 0, size: V::size_of() }; self.store(*ptr, index, value); } } @@ -366,3 +348,19 @@ impl + MemVariable> FromConstant for Array + MemVariable> FromConstant for Vec { + type Constant = Vec; + + fn constant(value: Self::Constant, builder: &mut Builder) -> Self { + value.into_iter().map(|x| V::constant(x, builder)).collect() + } +} + +impl + MemVariable, const N: usize> FromConstant for [V; N] { + type Constant = [V::Constant; N]; + + fn constant(value: Self::Constant, builder: &mut Builder) -> Self { + value.map(|x| V::constant(x, builder)) + } +} diff --git a/crates/recursion/compiler/src/ir/fold.rs b/crates/recursion/compiler/src/ir/fold.rs new file mode 100644 index 0000000000..59c8dd6a4d --- /dev/null +++ b/crates/recursion/compiler/src/ir/fold.rs @@ -0,0 +1,33 @@ +use sp1_recursion_derive::DslVariable; + +use super::{Ext, Felt, Var}; +use crate::ir::{Array, Builder, Config, MemIndex, MemVariable, Ptr, Variable}; + +#[derive(DslVariable, Debug, Clone)] +pub struct FriFoldInput { + pub z: Ext, + pub alpha: Ext, + pub x: Felt, + pub log_height: Var, + pub mat_opening: Array>, + pub ps_at_z: Array>, + pub alpha_pow: Array>, + pub ro: Array>, +} + +#[derive(Debug, Clone)] +pub struct CircuitV2FriFoldInput { + pub z: Ext, + pub alpha: Ext, + pub x: Felt, + pub mat_opening: Vec>, + pub ps_at_z: Vec>, + pub alpha_pow_input: Vec>, + pub ro_input: Vec>, +} + +#[derive(Debug, Clone)] +pub struct CircuitV2FriFoldOutput { + pub alpha_pow_output: Vec>, + pub ro_output: Vec>, +} diff --git a/recursion/compiler/src/ir/instructions.rs b/crates/recursion/compiler/src/ir/instructions.rs similarity index 78% rename from recursion/compiler/src/ir/instructions.rs rename to crates/recursion/compiler/src/ir/instructions.rs index 636f4c86a2..9c52cc7eb7 100644 --- a/recursion/compiler/src/ir/instructions.rs +++ b/crates/recursion/compiler/src/ir/instructions.rs @@ -1,5 +1,9 @@ -use super::{Array, FriFoldInput, MemIndex, Ptr, TracedVec}; -use super::{Config, Ext, Felt, Usize, Var}; +use sp1_recursion_core::air::RecursionPublicValues; + +use super::{ + Array, CircuitV2FriFoldInput, CircuitV2FriFoldOutput, Config, Ext, Felt, FriFoldInput, + MemIndex, Ptr, TracedVec, Usize, Var, +}; /// An intermeddiate instruction set for implementing programs. /// @@ -50,9 +54,11 @@ pub enum DslIr { SubFIN(Felt, C::F, Felt), /// Subtracts two extension field elements (ext = ext - ext). SubE(Ext, Ext, Ext), - /// Subtrancts an extension field element and an extension field immediate (ext = ext - ext field imm). + /// Subtrancts an extension field element and an extension field immediate (ext = ext - ext + /// field imm). SubEI(Ext, Ext, C::EF), - /// Subtracts an extension field immediate and an extension field element (ext = ext field imm - ext). + /// Subtracts an extension field immediate and an extension field element (ext = ext field imm + /// - ext). SubEIN(Ext, C::EF, Ext), /// Subtracts an extension field element and a field immediate (ext = ext - field imm). SubEFI(Ext, Ext, C::F), @@ -70,7 +76,8 @@ pub enum DslIr { MulFI(Felt, Felt, C::F), /// Multiplies two extension field elements (ext = ext * ext). MulE(Ext, Ext, Ext), - /// Multiplies an extension field element and an extension field immediate (ext = ext * ext field imm). + /// Multiplies an extension field element and an extension field immediate (ext = ext * ext + /// field imm). MulEI(Ext, Ext, C::EF), /// Multiplies an extension field element and a field immediate (ext = ext * field imm). MulEFI(Ext, Ext, C::F), @@ -86,9 +93,11 @@ pub enum DslIr { DivFIN(Felt, C::F, Felt), /// Divides two extension field elements (ext = ext / ext). DivE(Ext, Ext, Ext), - /// Divides an extension field element and an extension field immediate (ext = ext / ext field imm). + /// Divides an extension field element and an extension field immediate (ext = ext / ext field + /// imm). DivEI(Ext, Ext, C::EF), - /// Divides and extension field immediate and an extension field element (ext = ext field imm / ext). + /// Divides and extension field immediate and an extension field element (ext = ext field imm / + /// ext). DivEIN(Ext, C::EF, Ext), /// Divides an extension field element and a field immediate (ext = ext / field imm). DivEFI(Ext, Ext, C::F), @@ -112,32 +121,21 @@ pub enum DslIr { InvE(Ext, Ext), // Control flow. - /// Executes a for loop with the parameters (start step value, end step value, step size, step variable, body). - For( - Usize, - Usize, - C::N, - Var, - TracedVec>, - ), - /// Executes an equal conditional branch with the parameters (lhs var, rhs var, then body, else body). - IfEq( - Var, - Var, - TracedVec>, - TracedVec>, - ), - /// Executes a not equal conditional branch with the parameters (lhs var, rhs var, then body, else body). - IfNe( - Var, - Var, - TracedVec>, - TracedVec>, - ), - /// Executes an equal conditional branch with the parameters (lhs var, rhs imm, then body, else body). - IfEqI(Var, C::N, TracedVec>, TracedVec>), - /// Executes a not equal conditional branch with the parameters (lhs var, rhs imm, then body, else body). - IfNeI(Var, C::N, TracedVec>, TracedVec>), + /// Executes a for loop with the parameters (start step value, end step value, step size, step + /// variable, body). + For(Box<(Usize, Usize, C::N, Var, TracedVec>)>), + /// Executes an equal conditional branch with the parameters (lhs var, rhs var, then body, else + /// body). + IfEq(Box<(Var, Var, TracedVec>, TracedVec>)>), + /// Executes a not equal conditional branch with the parameters (lhs var, rhs var, then body, + /// else body). + IfNe(Box<(Var, Var, TracedVec>, TracedVec>)>), + /// Executes an equal conditional branch with the parameters (lhs var, rhs imm, then body, else + /// body). + IfEqI(Box<(Var, C::N, TracedVec>, TracedVec>)>), + /// Executes a not equal conditional branch with the parameters (lhs var, rhs imm, then body, + /// else body). + IfNeI(Box<(Var, C::N, TracedVec>, TracedVec>)>), /// Break out of a for loop. Break, @@ -162,9 +160,11 @@ pub enum DslIr { AssertEqFI(Felt, C::F), /// Assert that a field element is not equal to a field immediate (felt != field imm). AssertNeFI(Felt, C::F), - /// Assert that an extension field element is equal to an extension field immediate (ext == ext field imm). + /// Assert that an extension field element is equal to an extension field immediate (ext == ext + /// field imm). AssertEqEI(Ext, C::EF), - /// Assert that an extension field element is not equal to an extension field immediate (ext != ext field imm). + /// Assert that an extension field element is not equal to an extension field immediate (ext != + /// ext field imm). AssertNeEI(Ext, C::EF), // Memory instructions. @@ -187,29 +187,36 @@ pub enum DslIr { ReduceE(Ext), // Bits. - /// Decompose a variable into size bits (bits = num2bits(var, size)). Should only be used when target is a gnark circuit. + /// Decompose a variable into size bits (bits = num2bits(var, size)). Should only be used when + /// target is a gnark circuit. CircuitNum2BitsV(Var, usize, Vec>), - /// Decompose a field element into bits (bits = num2bits(felt)). Should only be used when target is a gnark circuit. + /// Decompose a field element into bits (bits = num2bits(felt)). Should only be used when + /// target is a gnark circuit. CircuitNum2BitsF(Felt, Vec>), + /// Convert a Felt to a Var in a circuit. Avoids decomposing to bits and then reconstructing. + CircuitFelt2Var(Felt, Var), // Hashing. /// Permutes an array of baby bear elements using Poseidon2 (output = p2_permute(array)). - Poseidon2PermuteBabyBear(Array>, Array>), - /// Compresses two baby bear element arrays using Poseidon2 (output = p2_compress(array1, array2)). + Poseidon2PermuteBabyBear(Box<(Array>, Array>)>), + /// Compresses two baby bear element arrays using Poseidon2 (output = p2_compress(array1, + /// array2)). Poseidon2CompressBabyBear( - Array>, - Array>, - Array>, + Box<(Array>, Array>, Array>)>, ), /// Absorb an array of baby bear elements for a specified hash instance. Poseidon2AbsorbBabyBear(Var, Array>), /// Finalize and return the hash digest of a specified hash instance. Poseidon2FinalizeBabyBear(Var, Array>), - /// Permutes an array of Bn254 elements using Poseidon2 (output = p2_permute(array)). Should only - /// be used when target is a gnark circuit. + /// Permutes an array of Bn254 elements using Poseidon2 (output = p2_permute(array)). Should + /// only be used when target is a gnark circuit. CircuitPoseidon2Permute([Var; 3]), /// Permutates an array of BabyBear elements in the circuit. - CircuitPoseidon2PermuteBabyBear([Felt; 16]), + CircuitPoseidon2PermuteBabyBear(Box<[Felt; 16]>), + /// Permutates an array of BabyBear elements in the circuit using the skinny precompile. + CircuitV2Poseidon2PermuteBabyBear(Box<([Felt; 16], [Felt; 16])>), + /// Commits the public values. + CircuitV2CommitPublicValues(Box>>), // Miscellaneous instructions. /// Decompose hint operation of a usize into an array. (output = num2bits(usize)). @@ -218,6 +225,8 @@ pub enum DslIr { HintBitsV(Array>, Var), /// Decompose hint operation of a field element into an array. (output = num2bits(felt)). HintBitsF(Array>, Felt), + /// Decompose hint operation of a field element into an array. (output = num2bits(felt)). + CircuitV2HintBitsF(Vec>, Felt), /// Prints a variable. PrintV(Var), /// Prints a field element. @@ -237,6 +246,10 @@ pub enum DslIr { HintFelts(Array>), /// Hint an array of extension field elements. HintExts(Array>), + /// Hint an array of field elements. + CircuitV2HintFelts(Vec>), + /// Hint an array of extension field elements. + CircuitV2HintExts(Vec>), /// Witness a variable. Should only be used when target is a gnark circuit. WitnessVar(Var, u32), /// Witness a field element. Should only be used when target is a gnark circuit. @@ -254,28 +267,27 @@ pub enum DslIr { /// Asserts that the inputted var is equal the circuit's vkey hash public input. Should only be /// used when target is a gnark circuit. CircuitCommitVkeyHash(Var), - /// Asserts that the inputted var is equal the circuit's commited values digest public input. Should - /// only be used when target is a gnark circuit. + /// Asserts that the inputted var is equal the circuit's commited values digest public input. + /// Should only be used when target is a gnark circuit. CircuitCommitCommitedValuesDigest(Var), // FRI specific instructions. - /// Executes a FRI fold operation. 1st field is the size of the fri fold input array. 2nd field - /// is the fri fold input array. See [`FriFoldInput`] for more details. + /// Executes a FRI fold operation. 1st field is the size of the fri fold input array. 2nd + /// field is the fri fold input array. See [`FriFoldInput`] for more details. FriFold(Var, Array>), + // FRI specific instructions. + /// Executes a FRI fold operation. Input is the fri fold input array. See [`FriFoldInput`] for + /// more details. + CircuitV2FriFold(Box<(CircuitV2FriFoldOutput, CircuitV2FriFoldInput)>), /// Select's a variable based on a condition. (select(cond, true_val, false_val) => output). /// Should only be used when target is a gnark circuit. CircuitSelectV(Var, Var, Var, Var), - /// Select's a field element based on a condition. (select(cond, true_val, false_val) => output). - /// Should only be used when target is a gnark circuit. + /// Select's a field element based on a condition. (select(cond, true_val, false_val) => + /// output). Should only be used when target is a gnark circuit. CircuitSelectF(Var, Felt, Felt, Felt), - /// Select's an extension field element based on a condition. (select(cond, true_val, false_val) => output). - /// Should only be used when target is a gnark circuit. - CircuitSelectE( - Var, - Ext, - Ext, - Ext, - ), + /// Select's an extension field element based on a condition. (select(cond, true_val, + /// false_val) => output). Should only be used when target is a gnark circuit. + CircuitSelectE(Var, Ext, Ext, Ext), /// Converts an ext to a slice of felts. Should only be used when target is a gnark circuit. CircuitExt2Felt([Felt; 4], Ext), /// Converts a slice of felts to an ext. Should only be used when target is a gnark circuit. @@ -286,7 +298,13 @@ pub enum DslIr { LessThan(Var, Var, Var), /// Tracks the number of cycles used by a block of code annotated by the string input. CycleTracker(String), + /// Tracks the number of cycles used by a block of code annotated by the string input. + CycleTrackerV2Enter(String), + /// Tracks the number of cycles used by a block of code annotated by the string input. + CycleTrackerV2Exit, // Reverse bits exponentiation. ExpReverseBitsLen(Ptr, Var, Var), + /// Reverse bits exponentiation. Output, base, exponent bits. + CircuitV2ExpReverseBits(Felt, Felt, Vec>), } diff --git a/recursion/compiler/src/ir/mod.rs b/crates/recursion/compiler/src/ir/mod.rs similarity index 100% rename from recursion/compiler/src/ir/mod.rs rename to crates/recursion/compiler/src/ir/mod.rs diff --git a/recursion/compiler/src/ir/poseidon.rs b/crates/recursion/compiler/src/ir/poseidon.rs similarity index 75% rename from recursion/compiler/src/ir/poseidon.rs rename to crates/recursion/compiler/src/ir/poseidon.rs index 2f7fde76ff..4ef469e5fb 100644 --- a/recursion/compiler/src/ir/poseidon.rs +++ b/crates/recursion/compiler/src/ir/poseidon.rs @@ -15,10 +15,8 @@ impl Builder { } Array::Dyn(_, len) => self.array::>(*len), }; - self.operations.push(DslIr::Poseidon2PermuteBabyBear( - output.clone(), - array.clone(), - )); + self.operations + .push(DslIr::Poseidon2PermuteBabyBear(Box::new((output.clone(), array.clone())))); output } @@ -26,10 +24,8 @@ impl Builder { /// /// Reference: [p3_poseidon2::Poseidon2] pub fn poseidon2_permute_mut(&mut self, array: &Array>) { - self.operations.push(DslIr::Poseidon2PermuteBabyBear( - array.clone(), - array.clone(), - )); + self.operations + .push(DslIr::Poseidon2PermuteBabyBear(Box::new((array.clone(), array.clone())))); } /// Applies the Poseidon2 absorb function to the given array. @@ -40,10 +36,7 @@ impl Builder { p2_hash_and_absorb_num: Var, input: &Array>, ) { - self.operations.push(DslIr::Poseidon2AbsorbBabyBear( - p2_hash_and_absorb_num, - input.clone(), - )); + self.operations.push(DslIr::Poseidon2AbsorbBabyBear(p2_hash_and_absorb_num, input.clone())); } /// Applies the Poseidon2 finalize to the given hash number. @@ -54,10 +47,7 @@ impl Builder { p2_hash_num: Var, output: &Array>, ) { - self.operations.push(DslIr::Poseidon2FinalizeBabyBear( - p2_hash_num, - output.clone(), - )); + self.operations.push(DslIr::Poseidon2FinalizeBabyBear(p2_hash_num, output.clone())); } /// Applies the Poseidon2 compression function to the given array. @@ -88,11 +78,11 @@ impl Builder { left: &Array>, right: &Array>, ) { - self.operations.push(DslIr::Poseidon2CompressBabyBear( + self.operations.push(DslIr::Poseidon2CompressBabyBear(Box::new(( result.clone(), left.clone(), right.clone(), - )); + )))); } /// Applies the Poseidon2 permutation to the given array. @@ -103,26 +93,24 @@ impl Builder { let break_flag: Var<_> = self.eval(C::N::zero()); let last_index: Usize<_> = self.eval(array.len() - 1); - self.range(0, array.len()) - .step_by(HASH_RATE) - .for_each(|i, builder| { - builder.if_eq(break_flag, C::N::one()).then(|builder| { + self.range(0, array.len()).step_by(HASH_RATE).for_each(|i, builder| { + builder.if_eq(break_flag, C::N::one()).then(|builder| { + builder.break_loop(); + }); + // Insert elements of the chunk. + builder.range(0, HASH_RATE).for_each(|j, builder| { + let index: Var<_> = builder.eval(i + j); + let element = builder.get(array, index); + builder.set_value(&mut state, j, element); + builder.if_eq(index, last_index).then(|builder| { + builder.assign(break_flag, C::N::one()); builder.break_loop(); }); - // Insert elements of the chunk. - builder.range(0, HASH_RATE).for_each(|j, builder| { - let index: Var<_> = builder.eval(i + j); - let element = builder.get(array, index); - builder.set_value(&mut state, j, element); - builder.if_eq(index, last_index).then(|builder| { - builder.assign(break_flag, C::N::one()); - builder.break_loop(); - }); - }); - - builder.poseidon2_permute_mut(&state); }); + builder.poseidon2_permute_mut(&state); + }); + state.truncate(self, Usize::Const(DIGEST_SIZE)); state } @@ -169,12 +157,10 @@ impl Builder { let felt = builder.get(&felts, i); builder.set_value(&mut state, idx, felt); builder.assign(idx, idx + C::N::one()); - builder - .if_eq(idx, C::N::from_canonical_usize(HASH_RATE)) - .then(|builder| { - builder.poseidon2_permute_mut(&state); - builder.assign(idx, C::N::zero()); - }); + builder.if_eq(idx, C::N::from_canonical_usize(HASH_RATE)).then(|builder| { + builder.poseidon2_permute_mut(&state); + builder.assign(idx, C::N::zero()); + }); } }); }); diff --git a/recursion/compiler/src/ir/ptr.rs b/crates/recursion/compiler/src/ir/ptr.rs similarity index 68% rename from recursion/compiler/src/ir/ptr.rs rename to crates/recursion/compiler/src/ir/ptr.rs index caa8012e1a..daf658d85f 100644 --- a/recursion/compiler/src/ir/ptr.rs +++ b/crates/recursion/compiler/src/ir/ptr.rs @@ -37,9 +37,7 @@ impl Variable for Ptr { type Expression = SymbolicPtr; fn uninit(builder: &mut Builder) -> Self { - Ptr { - address: Var::uninit(builder), - } + Ptr { address: Var::uninit(builder) } } fn assign(&self, src: Self::Expression, builder: &mut Builder) { @@ -79,9 +77,7 @@ impl MemVariable for Ptr { impl From> for SymbolicPtr { fn from(ptr: Ptr) -> Self { - SymbolicPtr { - address: SymbolicVar::from(ptr.address), - } + SymbolicPtr { address: SymbolicVar::from(ptr.address) } } } @@ -89,9 +85,7 @@ impl Add for Ptr { type Output = SymbolicPtr; fn add(self, rhs: Self) -> Self::Output { - SymbolicPtr { - address: self.address + rhs.address, - } + SymbolicPtr { address: self.address + rhs.address } } } @@ -99,9 +93,7 @@ impl Sub for Ptr { type Output = SymbolicPtr; fn sub(self, rhs: Self) -> Self::Output { - SymbolicPtr { - address: self.address - rhs.address, - } + SymbolicPtr { address: self.address - rhs.address } } } @@ -109,9 +101,7 @@ impl Add for SymbolicPtr { type Output = Self; fn add(self, rhs: Self) -> Self { - Self { - address: self.address + rhs.address, - } + Self { address: self.address + rhs.address } } } @@ -119,9 +109,7 @@ impl Sub for SymbolicPtr { type Output = Self; fn sub(self, rhs: Self) -> Self { - Self { - address: self.address - rhs.address, - } + Self { address: self.address - rhs.address } } } @@ -129,9 +117,7 @@ impl Add> for SymbolicPtr { type Output = Self; fn add(self, rhs: Ptr) -> Self { - Self { - address: self.address + rhs.address, - } + Self { address: self.address + rhs.address } } } @@ -139,9 +125,7 @@ impl Sub> for SymbolicPtr { type Output = Self; fn sub(self, rhs: Ptr) -> Self { - Self { - address: self.address - rhs.address, - } + Self { address: self.address - rhs.address } } } @@ -149,9 +133,7 @@ impl Add> for Ptr { type Output = SymbolicPtr; fn add(self, rhs: SymbolicPtr) -> SymbolicPtr { - SymbolicPtr { - address: self.address + rhs.address, - } + SymbolicPtr { address: self.address + rhs.address } } } @@ -159,9 +141,7 @@ impl Add> for Ptr { type Output = SymbolicPtr; fn add(self, rhs: SymbolicVar) -> SymbolicPtr { - SymbolicPtr { - address: self.address + rhs, - } + SymbolicPtr { address: self.address + rhs } } } @@ -169,9 +149,7 @@ impl Sub> for Ptr { type Output = SymbolicPtr; fn sub(self, rhs: SymbolicVar) -> SymbolicPtr { - SymbolicPtr { - address: self.address - rhs, - } + SymbolicPtr { address: self.address - rhs } } } @@ -179,9 +157,7 @@ impl Sub> for Ptr { type Output = SymbolicPtr; fn sub(self, rhs: SymbolicPtr) -> SymbolicPtr { - SymbolicPtr { - address: self.address - rhs.address, - } + SymbolicPtr { address: self.address - rhs.address } } } @@ -190,12 +166,10 @@ impl Add> for Ptr { fn add(self, rhs: Usize) -> SymbolicPtr { match rhs { - Usize::Const(rhs) => SymbolicPtr { - address: self.address + N::from_canonical_usize(rhs), - }, - Usize::Var(rhs) => SymbolicPtr { - address: self.address + rhs, - }, + Usize::Const(rhs) => { + SymbolicPtr { address: self.address + N::from_canonical_usize(rhs) } + } + Usize::Var(rhs) => SymbolicPtr { address: self.address + rhs }, } } } @@ -205,12 +179,10 @@ impl Add> for SymbolicPtr { fn add(self, rhs: Usize) -> SymbolicPtr { match rhs { - Usize::Const(rhs) => SymbolicPtr { - address: self.address + N::from_canonical_usize(rhs), - }, - Usize::Var(rhs) => SymbolicPtr { - address: self.address + rhs, - }, + Usize::Const(rhs) => { + SymbolicPtr { address: self.address + N::from_canonical_usize(rhs) } + } + Usize::Var(rhs) => SymbolicPtr { address: self.address + rhs }, } } } @@ -220,12 +192,10 @@ impl Sub> for Ptr { fn sub(self, rhs: Usize) -> SymbolicPtr { match rhs { - Usize::Const(rhs) => SymbolicPtr { - address: self.address - N::from_canonical_usize(rhs), - }, - Usize::Var(rhs) => SymbolicPtr { - address: self.address - rhs, - }, + Usize::Const(rhs) => { + SymbolicPtr { address: self.address - N::from_canonical_usize(rhs) } + } + Usize::Var(rhs) => SymbolicPtr { address: self.address - rhs }, } } } @@ -235,12 +205,10 @@ impl Sub> for SymbolicPtr { fn sub(self, rhs: Usize) -> SymbolicPtr { match rhs { - Usize::Const(rhs) => SymbolicPtr { - address: self.address - N::from_canonical_usize(rhs), - }, - Usize::Var(rhs) => SymbolicPtr { - address: self.address - rhs, - }, + Usize::Const(rhs) => { + SymbolicPtr { address: self.address - N::from_canonical_usize(rhs) } + } + Usize::Var(rhs) => SymbolicPtr { address: self.address - rhs }, } } } diff --git a/recursion/compiler/src/ir/symbolic.rs b/crates/recursion/compiler/src/ir/symbolic.rs similarity index 94% rename from recursion/compiler/src/ir/symbolic.rs rename to crates/recursion/compiler/src/ir/symbolic.rs index 6b2fbfd4e1..1ff565c7b9 100644 --- a/recursion/compiler/src/ir/symbolic.rs +++ b/crates/recursion/compiler/src/ir/symbolic.rs @@ -1,17 +1,19 @@ use alloc::rc::Rc; -use core::any::Any; -use core::ops::{Add, Div, Mul, Neg, Sub}; -use std::any::TypeId; -use std::hash::Hash; -use std::iter::{Product, Sum}; -use std::mem; -use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; - -use p3_field::{AbstractField, ExtensionField}; -use p3_field::{Field, FieldArray}; - -use super::Usize; -use super::{Ext, Felt, Var}; +use core::{ + any::Any, + ops::{Add, Div, Mul, Neg, Sub}, +}; +use std::{ + any::TypeId, + hash::Hash, + iter::{Product, Sum}, + mem, + ops::{AddAssign, DivAssign, MulAssign, SubAssign}, +}; + +use p3_field::{AbstractField, ExtensionField, Field, FieldArray}; + +use super::{Ext, Felt, Usize, Var}; const NUM_RANDOM_ELEMENTS: usize = 4; @@ -33,20 +35,16 @@ pub fn ext_elements>() -> Digest { fn digest_id(id: u32) -> Digest { let elements = elements(); - Digest::from(elements.0.map(|e: F| { - (e + F::from_canonical_u32(id)) - .try_inverse() - .unwrap_or(F::one()) - })) + Digest::from( + elements.0.map(|e: F| (e + F::from_canonical_u32(id)).try_inverse().unwrap_or(F::one())), + ) } fn digest_id_ext>(id: u32) -> Digest { let elements = ext_elements(); - Digest::from(elements.0.map(|e: EF| { - (e + EF::from_canonical_u32(id)) - .try_inverse() - .unwrap_or(EF::one()) - })) + Digest::from( + elements.0.map(|e: EF| (e + EF::from_canonical_u32(id)).try_inverse().unwrap_or(EF::one())), + ) } fn div_digests(a: Digest, b: Digest) -> Digest { @@ -491,10 +489,7 @@ impl, E: Any> Mul for SymbolicExt { match rhs { ExtOperand::Base(f) => SymbolicExt::Mul( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), prod_digest, ), ExtOperand::Const(ef) => SymbolicExt::Mul( @@ -504,10 +499,7 @@ impl, E: Any> Mul for SymbolicExt { ), ExtOperand::Felt(f) => SymbolicExt::Mul( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), prod_digest, ), ExtOperand::Ext(e) => SymbolicExt::Mul( @@ -553,30 +545,20 @@ impl, E: Any> Sub for SymbolicExt { match rhs { ExtOperand::Base(f) => SymbolicExt::Sub( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), - digest, - ), - ExtOperand::Const(ef) => SymbolicExt::Sub( - Rc::new(self), - Rc::new(SymbolicExt::Const(ef, rhs_digest)), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), digest, ), + ExtOperand::Const(ef) => { + SymbolicExt::Sub(Rc::new(self), Rc::new(SymbolicExt::Const(ef, rhs_digest)), digest) + } ExtOperand::Felt(f) => SymbolicExt::Sub( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), - digest, - ), - ExtOperand::Ext(e) => SymbolicExt::Sub( - Rc::new(self), - Rc::new(SymbolicExt::Val(e, rhs_digest)), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), digest, ), + ExtOperand::Ext(e) => { + SymbolicExt::Sub(Rc::new(self), Rc::new(SymbolicExt::Val(e, rhs_digest)), digest) + } ExtOperand::SymFelt(f) => SymbolicExt::Sub( Rc::new(self), Rc::new(SymbolicExt::Base(Rc::new(f), rhs_digest)), @@ -608,30 +590,20 @@ impl, E: Any> Div for SymbolicExt { match rhs { ExtOperand::Base(f) => SymbolicExt::Div( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), - digest, - ), - ExtOperand::Const(ef) => SymbolicExt::Div( - Rc::new(self), - Rc::new(SymbolicExt::Const(ef, rhs_digest)), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), digest, ), + ExtOperand::Const(ef) => { + SymbolicExt::Div(Rc::new(self), Rc::new(SymbolicExt::Const(ef, rhs_digest)), digest) + } ExtOperand::Felt(f) => SymbolicExt::Div( Rc::new(self), - Rc::new(SymbolicExt::Base( - Rc::new(SymbolicFelt::from(f)), - rhs_digest, - )), - digest, - ), - ExtOperand::Ext(e) => SymbolicExt::Div( - Rc::new(self), - Rc::new(SymbolicExt::Val(e, rhs_digest)), + Rc::new(SymbolicExt::Base(Rc::new(SymbolicFelt::from(f)), rhs_digest)), digest, ), + ExtOperand::Ext(e) => { + SymbolicExt::Div(Rc::new(self), Rc::new(SymbolicExt::Val(e, rhs_digest)), digest) + } ExtOperand::SymFelt(f) => SymbolicExt::Div( Rc::new(self), Rc::new(SymbolicExt::Base(Rc::new(f), rhs_digest)), @@ -669,7 +641,8 @@ impl> Neg for SymbolicExt { } } -// Implement all operations between N, F, EF, and SymbolicVar, SymbolicFelt, SymbolicExt +// Implement all operations between N, F, EF, and SymbolicVar, SymbolicFelt, SymbolicExt impl Add for SymbolicVar { type Output = Self; @@ -1123,6 +1096,14 @@ impl, E: Any> DivAssign for SymbolicExt> Mul> for SymbolicFelt { + type Output = SymbolicExt; + + fn mul(self, rhs: SymbolicExt) -> Self::Output { + rhs * self + } +} + impl, E: Any> ExtensionOperand for E { fn to_operand(self) -> ExtOperand { match self.type_id() { diff --git a/recursion/compiler/src/ir/types.rs b/crates/recursion/compiler/src/ir/types.rs similarity index 96% rename from recursion/compiler/src/ir/types.rs rename to crates/recursion/compiler/src/ir/types.rs index c30c8fa4a4..2cbef531e5 100644 --- a/recursion/compiler/src/ir/types.rs +++ b/crates/recursion/compiler/src/ir/types.rs @@ -1,21 +1,14 @@ use alloc::format; use core::marker::PhantomData; -use std::collections::HashMap; -use std::hash::Hash; - -use p3_field::AbstractField; -use p3_field::ExtensionField; -use p3_field::Field; -use serde::Deserialize; -use serde::Serialize; - -use super::ExtConst; -use super::FromConstant; -use super::MemIndex; -use super::MemVariable; -use super::Ptr; -use super::SymbolicUsize; -use super::{Builder, Config, DslIr, SymbolicExt, SymbolicFelt, SymbolicVar, Variable}; +use std::{collections::HashMap, hash::Hash}; + +use p3_field::{AbstractField, ExtensionField, Field}; +use serde::{Deserialize, Serialize}; + +use super::{ + Builder, Config, DslIr, ExtConst, FromConstant, MemIndex, MemVariable, Ptr, SymbolicExt, + SymbolicFelt, SymbolicUsize, SymbolicVar, Variable, +}; /// A variable that represents a native field element. /// @@ -230,9 +223,7 @@ impl Var { cache: &mut HashMap, Self>, ) { if let Some(v) = cache.get(&src) { - builder - .operations - .push(DslIr::AddVI(*self, *v, C::N::zero())); + builder.operations.push(DslIr::AddVI(*self, *v, C::N::zero())); return; } match src { @@ -240,9 +231,7 @@ impl Var { builder.operations.push(DslIr::ImmV(*self, c)); } SymbolicVar::Val(v, _) => { - builder - .operations - .push(DslIr::AddVI(*self, v, C::N::zero())); + builder.operations.push(DslIr::AddVI(*self, v, C::N::zero())); } SymbolicVar::Add(lhs, rhs, _) => match (&*lhs, &*rhs) { (SymbolicVar::Const(lhs, _), SymbolicVar::Const(rhs, _)) => { @@ -407,8 +396,8 @@ impl Variable for Var { type Expression = SymbolicVar; fn uninit(builder: &mut Builder) -> Self { - let var = Var(builder.var_count, PhantomData); - builder.var_count += 1; + let var = Var(builder.variable_count, PhantomData); + builder.variable_count += 1; var } @@ -521,9 +510,7 @@ impl Felt { cache: &mut HashMap, Self>, ) { if let Some(v) = cache.get(&src) { - builder - .operations - .push(DslIr::AddFI(*self, *v, C::F::zero())); + builder.operations.push(DslIr::AddFI(*self, *v, C::F::zero())); return; } match src { @@ -531,9 +518,7 @@ impl Felt { builder.operations.push(DslIr::ImmF(*self, c)); } SymbolicFelt::Val(v, _) => { - builder - .operations - .push(DslIr::AddFI(*self, v, C::F::zero())); + builder.operations.push(DslIr::AddFI(*self, v, C::F::zero())); } SymbolicFelt::Add(lhs, rhs, _) => match (&*lhs, &*rhs) { (SymbolicFelt::Const(lhs, _), SymbolicFelt::Const(rhs, _)) => { @@ -750,8 +735,8 @@ impl Variable for Felt { type Expression = SymbolicFelt; fn uninit(builder: &mut Builder) -> Self { - let felt = Felt(builder.felt_count, PhantomData); - builder.felt_count += 1; + let felt = Felt(builder.variable_count, PhantomData); + builder.variable_count += 1; felt } @@ -865,22 +850,16 @@ impl> Ext { base_cache: &mut HashMap, Felt>, ) { if let Some(v) = ext_cache.get(&src) { - builder - .operations - .push(DslIr::AddEI(*self, *v, C::EF::zero())); + builder.operations.push(DslIr::AddEI(*self, *v, C::EF::zero())); return; } match src { SymbolicExt::Base(v, _) => match &*v { SymbolicFelt::Const(c, _) => { - builder - .operations - .push(DslIr::ImmE(*self, C::EF::from_base(*c))); + builder.operations.push(DslIr::ImmE(*self, C::EF::from_base(*c))); } SymbolicFelt::Val(v, _) => { - builder - .operations - .push(DslIr::AddEFFI(*self, *v, C::EF::zero())); + builder.operations.push(DslIr::AddEFFI(*self, *v, C::EF::zero())); } v => { let v_value = Felt::uninit(builder); @@ -892,9 +871,7 @@ impl> Ext { builder.operations.push(DslIr::ImmE(*self, c)); } SymbolicExt::Val(v, _) => { - builder - .operations - .push(DslIr::AddEI(*self, v, C::EF::zero())); + builder.operations.push(DslIr::AddEI(*self, v, C::EF::zero())); } SymbolicExt::Add(lhs, rhs, _) => match (&*lhs, &*rhs) { (SymbolicExt::Const(lhs, _), SymbolicExt::Const(rhs, _)) => { @@ -916,9 +893,7 @@ impl> Ext { let rhs_value: Felt<_> = Felt::uninit(builder); rhs_value.assign_with_cache(rhs.clone(), builder, base_cache); base_cache.insert(rhs.clone(), rhs_value); - builder - .operations - .push(DslIr::AddEFFI(*self, rhs_value, *lhs)); + builder.operations.push(DslIr::AddEFFI(*self, rhs_value, *lhs)); } }, (SymbolicExt::Const(lhs, _), rhs) => { @@ -1144,8 +1119,8 @@ impl Variable for Ext { type Expression = SymbolicExt; fn uninit(builder: &mut Builder) -> Self { - let ext = Ext(builder.ext_count, PhantomData); - builder.ext_count += 1; + let ext = Ext(builder.variable_count, PhantomData); + builder.variable_count += 1; ext } diff --git a/recursion/compiler/src/ir/utils.rs b/crates/recursion/compiler/src/ir/utils.rs similarity index 95% rename from recursion/compiler/src/ir/utils.rs rename to crates/recursion/compiler/src/ir/utils.rs index 5c161a85ca..0276d6eac5 100644 --- a/recursion/compiler/src/ir/utils.rs +++ b/crates/recursion/compiler/src/ir/utils.rs @@ -155,12 +155,9 @@ impl Builder { _ => panic!("Expected a dynamic array"), }; - // Call the DslIR instruction ExpReverseBitsLen, which modifies the memory pointed to by `x_copy_arr_ptr`. - self.push(DslIr::ExpReverseBitsLen( - x_copy_arr_ptr, - ptr.address, - bit_len_var, - )); + // Call the DslIR instruction ExpReverseBitsLen, which modifies the memory pointed to by + // `x_copy_arr_ptr`. + self.push(DslIr::ExpReverseBitsLen(x_copy_arr_ptr, ptr.address, bit_len_var)); // Return the value stored at the address pointed to by `x_copy_arr_ptr`. self.get(&x_copy_arr, 0) @@ -213,8 +210,7 @@ impl Builder { V: Variable + Copy + Add, { let result: V = self.eval(base); - self.range(0, shift) - .for_each(|_, builder| builder.assign(result, result + result)); + self.range(0, shift).for_each(|_, builder| builder.assign(result, result + result)); result } @@ -238,8 +234,7 @@ impl Builder { /// Converts an ext to a slice of felts. pub fn ext2felt(&mut self, value: Ext) -> Array> { let result = self.dyn_array(4); - self.operations - .push(DslIr::HintExt2Felt(result.clone(), value)); + self.operations.push(DslIr::HintExt2Felt(result.clone(), value)); // Verify that the decomposed extension element is correct. let mut reconstructed_ext: Ext = self.constant(C::EF::zero()); @@ -260,8 +255,7 @@ impl Builder { let b = self.uninit(); let c = self.uninit(); let d = self.uninit(); - self.operations - .push(DslIr::CircuitExt2Felt([a, b, c, d], value)); + self.operations.push(DslIr::CircuitExt2Felt([a, b, c, d], value)); [a, b, c, d] } } @@ -271,10 +265,10 @@ mod tests { use p3_field::PrimeField32; use p3_util::reverse_bits_len; use rand::{thread_rng, Rng}; - use sp1_core::{stark::StarkGenericConfig, utils::BabyBearPoseidon2}; use sp1_recursion_core::runtime::{Runtime, NUM_BITS}; use p3_field::AbstractField; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use crate::{ asm::AsmBuilder, diff --git a/recursion/compiler/src/ir/var.rs b/crates/recursion/compiler/src/ir/var.rs similarity index 100% rename from recursion/compiler/src/ir/var.rs rename to crates/recursion/compiler/src/ir/var.rs diff --git a/recursion/compiler/src/lib.rs b/crates/recursion/compiler/src/lib.rs similarity index 78% rename from recursion/compiler/src/lib.rs rename to crates/recursion/compiler/src/lib.rs index 210d4b22a6..c4ebc5bb10 100644 --- a/recursion/compiler/src/lib.rs +++ b/crates/recursion/compiler/src/lib.rs @@ -4,12 +4,12 @@ extern crate alloc; pub mod asm; +pub mod circuit; pub mod config; pub mod constraints; pub mod ir; pub mod prelude { - pub use crate::asm::AsmCompiler; - pub use crate::ir::*; + pub use crate::{asm::AsmCompiler, ir::*}; pub use sp1_recursion_derive::DslVariable; } diff --git a/recursion/compiler/tests/arithmetic.rs b/crates/recursion/compiler/tests/arithmetic.rs similarity index 93% rename from recursion/compiler/tests/arithmetic.rs rename to crates/recursion/compiler/tests/arithmetic.rs index 54148d57ec..d218854019 100644 --- a/recursion/compiler/tests/arithmetic.rs +++ b/crates/recursion/compiler/tests/arithmetic.rs @@ -1,12 +1,12 @@ use rand::{thread_rng, Rng}; use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::ir::{Ext, Felt, SymbolicExt}; -use sp1_recursion_compiler::ir::{ExtConst, Var}; +use sp1_recursion_compiler::{ + asm::AsmBuilder, + ir::{Ext, ExtConst, Felt, SymbolicExt, Var}, +}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_compiler_arithmetic() { diff --git a/recursion/compiler/tests/array.rs b/crates/recursion/compiler/tests/array.rs similarity index 89% rename from recursion/compiler/tests/array.rs rename to crates/recursion/compiler/tests/array.rs index 0781f84b39..71dedb5485 100644 --- a/recursion/compiler/tests/array.rs +++ b/crates/recursion/compiler/tests/array.rs @@ -1,19 +1,13 @@ use rand::{thread_rng, Rng}; use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Builder; -use sp1_recursion_compiler::ir::ExtConst; -use sp1_recursion_compiler::ir::MemIndex; -use sp1_recursion_compiler::ir::MemVariable; -use sp1_recursion_compiler::ir::Ptr; -use sp1_recursion_compiler::ir::Variable; -use sp1_recursion_compiler::ir::{Config, Ext, Felt, Var}; +use sp1_recursion_compiler::{ + asm::AsmBuilder, + ir::{Array, Builder, Config, Ext, ExtConst, Felt, MemIndex, MemVariable, Ptr, Var, Variable}, +}; use sp1_recursion_core::runtime::Runtime; use sp1_recursion_derive::DslVariable; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[derive(DslVariable, Clone, Debug)] pub struct Point { diff --git a/recursion/compiler/tests/conditionals.rs b/crates/recursion/compiler/tests/conditionals.rs similarity index 75% rename from recursion/compiler/tests/conditionals.rs rename to crates/recursion/compiler/tests/conditionals.rs index c3f01eb1aa..41827a42ed 100644 --- a/recursion/compiler/tests/conditionals.rs +++ b/crates/recursion/compiler/tests/conditionals.rs @@ -1,10 +1,8 @@ use p3_baby_bear::BabyBear; -use p3_field::extension::BinomialExtensionField; -use p3_field::AbstractField; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::ir::Var; +use p3_field::{extension::BinomialExtensionField, AbstractField}; +use sp1_recursion_compiler::{asm::AsmBuilder, ir::Var}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::baby_bear_poseidon2::BabyBearPoseidon2; #[test] fn test_compiler_conditionals() { @@ -24,9 +22,7 @@ fn test_compiler_conditionals() { builder.if_eq(one, one).then(|builder| { builder.if_eq(two, two).then(|builder| { builder.if_eq(three, three).then(|builder| { - builder - .if_eq(four, four) - .then(|builder| builder.assign(c, F::one())) + builder.if_eq(four, four).then(|builder| builder.assign(c, F::one())) }) }) }) @@ -36,16 +32,12 @@ fn test_compiler_conditionals() { let c: Var<_> = builder.eval(F::zero()); builder.if_eq(zero, one).then_or_else( |builder| { - builder.if_eq(one, one).then(|builder| { - builder - .if_eq(two, two) - .then(|builder| builder.assign(c, F::one())) - }) + builder + .if_eq(one, one) + .then(|builder| builder.if_eq(two, two).then(|builder| builder.assign(c, F::one()))) }, |builder| { - builder - .if_ne(three, four) - .then_or_else(|_| {}, |builder| builder.assign(c, F::zero())) + builder.if_ne(three, four).then_or_else(|_| {}, |builder| builder.assign(c, F::zero())) }, ); builder.assert_var_eq(c, F::zero()); @@ -78,9 +70,7 @@ fn test_compiler_conditionals_v2() { builder.if_eq(one, one).then(|builder| { builder.if_eq(two, two).then(|builder| { builder.if_eq(three, three).then(|builder| { - builder - .if_eq(four, four) - .then(|builder| builder.assign(c, F::one())) + builder.if_eq(four, four).then(|builder| builder.assign(c, F::one())) }) }) }) diff --git a/recursion/compiler/tests/for_loops.rs b/crates/recursion/compiler/tests/for_loops.rs similarity index 90% rename from recursion/compiler/tests/for_loops.rs rename to crates/recursion/compiler/tests/for_loops.rs index b4227c0b40..b57fe3e43c 100644 --- a/recursion/compiler/tests/for_loops.rs +++ b/crates/recursion/compiler/tests/for_loops.rs @@ -1,13 +1,11 @@ use p3_baby_bear::BabyBear; use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::asm::AsmConfig; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::SymbolicVar; -use sp1_recursion_compiler::ir::Var; +use sp1_recursion_compiler::{ + asm::{AsmBuilder, AsmConfig}, + ir::{Array, SymbolicVar, Var}, +}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_compiler_for_loops() { @@ -105,9 +103,7 @@ fn test_compiler_break() { builder.range(0, array.len()).for_each(|i, builder| { builder.set(&mut array, i, i); - builder - .if_eq(i, break_len) - .then(|builder| builder.break_loop()); + builder.if_eq(i, break_len).then(|builder| builder.break_loop()); }); // Test that the array is correctly initialized. @@ -128,9 +124,7 @@ fn test_compiler_break() { let exp_value: Var<_> = builder.eval(i * is_break); let value = builder.get(&array, i); builder.assert_var_eq(value, exp_value); - builder - .if_eq(i, break_len) - .then(|builder| builder.assign(is_break, F::zero())); + builder.if_eq(i, break_len).then(|builder| builder.assign(is_break, F::zero())); }); // Test the break instructions in a nested loop. @@ -141,9 +135,7 @@ fn test_compiler_break() { builder.range(0, i).for_each(|_, builder| { builder.assign(counter, counter + F::one()); - builder - .if_eq(counter, break_len) - .then(|builder| builder.break_loop()); + builder.if_eq(counter, break_len).then(|builder| builder.break_loop()); }); builder.set(&mut array, i, counter); @@ -157,9 +149,7 @@ fn test_compiler_break() { builder.eval(i * is_break + (SymbolicVar::::one() - is_break) * break_len); let value = builder.get(&array, i); builder.assert_var_eq(value, exp_value); - builder - .if_eq(i, break_len) - .then(|builder| builder.assign(is_break, F::zero())); + builder.if_eq(i, break_len).then(|builder| builder.assign(is_break, F::zero())); }); let code = builder.compile_asm(); diff --git a/recursion/compiler/tests/io.rs b/crates/recursion/compiler/tests/io.rs similarity index 94% rename from recursion/compiler/tests/io.rs rename to crates/recursion/compiler/tests/io.rs index 7ca97a07b2..4ba5a86545 100644 --- a/recursion/compiler/tests/io.rs +++ b/crates/recursion/compiler/tests/io.rs @@ -1,8 +1,7 @@ use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; use sp1_recursion_compiler::asm::AsmBuilder; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_io() { diff --git a/recursion/compiler/tests/lt.rs b/crates/recursion/compiler/tests/lt.rs similarity index 84% rename from recursion/compiler/tests/lt.rs rename to crates/recursion/compiler/tests/lt.rs index 72ae9d82e6..698db8fcb4 100644 --- a/recursion/compiler/tests/lt.rs +++ b/crates/recursion/compiler/tests/lt.rs @@ -1,9 +1,7 @@ use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::prelude::*; +use sp1_recursion_compiler::{asm::AsmBuilder, prelude::*}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_compiler_less_than() { diff --git a/recursion/compiler/tests/poseidon2.rs b/crates/recursion/compiler/tests/poseidon2.rs similarity index 91% rename from recursion/compiler/tests/poseidon2.rs rename to crates/recursion/compiler/tests/poseidon2.rs index d6a6f65cfb..6cad8032f2 100644 --- a/recursion/compiler/tests/poseidon2.rs +++ b/crates/recursion/compiler/tests/poseidon2.rs @@ -1,16 +1,13 @@ -use p3_field::AbstractField; -use p3_field::PrimeField32; +use p3_field::{AbstractField, PrimeField32}; use p3_symmetric::Permutation; -use rand::thread_rng; -use rand::Rng; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::setup_logger; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Var; -use sp1_recursion_core::runtime::Runtime; -use sp1_recursion_core::runtime::PERMUTATION_WIDTH; +use rand::{thread_rng, Rng}; +use sp1_core_machine::utils::setup_logger; +use sp1_recursion_compiler::{ + asm::AsmBuilder, + ir::{Array, Var}, +}; +use sp1_recursion_core::runtime::{Runtime, PERMUTATION_WIDTH}; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_compiler_poseidon2_permute() { diff --git a/recursion/compiler/tests/public_values.rs b/crates/recursion/compiler/tests/public_values.rs similarity index 85% rename from recursion/compiler/tests/public_values.rs rename to crates/recursion/compiler/tests/public_values.rs index 1ad7f3fe77..02115ab621 100644 --- a/recursion/compiler/tests/public_values.rs +++ b/crates/recursion/compiler/tests/public_values.rs @@ -1,9 +1,7 @@ use p3_field::AbstractField; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmBuilder; -use sp1_recursion_compiler::prelude::*; +use sp1_recursion_compiler::{asm::AsmBuilder, prelude::*}; use sp1_recursion_core::runtime::Runtime; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; #[test] fn test_compiler_public_values() { diff --git a/crates/recursion/core-v2/CHANGELOG.md b/crates/recursion/core-v2/CHANGELOG.md new file mode 100644 index 0000000000..efcaa44f4e --- /dev/null +++ b/crates/recursion/core-v2/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-recursion-core-v2-v1.2.0-rc1) - 2024-08-23 + +### Fixed + +- bug in exp_reverse_bits memory multiplicity ([#1378](https://github.com/succinctlabs/sp1/pull/1378)) +- fix imports +- cargo check on tests + +### Other + +- use crate `vec_map`, box large `Instruction` variants ([#1360](https://github.com/succinctlabs/sp1/pull/1360)) +- merge dev into experimental pt 2 ([#1341](https://github.com/succinctlabs/sp1/pull/1341)) +- resolve merge conflicts between dev and experimental diff --git a/crates/recursion/core-v2/Cargo.toml b/crates/recursion/core-v2/Cargo.toml new file mode 100644 index 0000000000..e2fb7cf83f --- /dev/null +++ b/crates/recursion/core-v2/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "sp1-recursion-core-v2" +description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." +readme = "../../../README.md" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } + +[dependencies] +p3-field = { workspace = true } +p3-util = { workspace = true } +p3-baby-bear = { workspace = true } +p3-air = { workspace = true } +p3-matrix = { workspace = true } +p3-maybe-rayon = { workspace = true } +p3-poseidon2 = { workspace = true } +p3-symmetric = { workspace = true } +sp1-derive = { workspace = true } +sp1-primitives = { workspace = true } +tracing = "0.1.40" +sp1-core-machine = { workspace = true } +sp1-core-executor = { workspace = true } +sp1-stark = { workspace = true } +sp1-recursion-core = { workspace = true } +hashbrown = { version = "0.14.5", features = ["serde"] } +itertools = "0.13.0" +p3-bn254-fr = { workspace = true } +p3-merkle-tree = { workspace = true } +p3-commit = { workspace = true } +p3-dft = { workspace = true } +p3-challenger = { workspace = true } +p3-fri = { workspace = true } +zkhash = "0.2.0" +ff = { version = "0.13", features = ["derive", "derive_bits"] } +serde = { version = "1.0", features = ["derive", "rc"] } +serde_with = "3.9.0" +backtrace = { version = "0.3.71", features = ["serde"] } +arrayref = "0.3.7" +static_assertions = "1.1.0" +num_cpus = "1.16.0" +thiserror = "1.0.60" +vec_map = "0.8.2" + +[dev-dependencies] +rand = "0.8.5" diff --git a/crates/recursion/core-v2/src/air.rs b/crates/recursion/core-v2/src/air.rs new file mode 100644 index 0000000000..8fffef0115 --- /dev/null +++ b/crates/recursion/core-v2/src/air.rs @@ -0,0 +1,2 @@ +// Export all the air stuff from `sp1_recursion_core` for now, until we will migrate it here. +pub use sp1_recursion_core::air::*; diff --git a/crates/recursion/core-v2/src/builder.rs b/crates/recursion/core-v2/src/builder.rs new file mode 100644 index 0000000000..1542081a6c --- /dev/null +++ b/crates/recursion/core-v2/src/builder.rs @@ -0,0 +1,65 @@ +use p3_air::AirBuilderWithPublicValues; +use p3_field::AbstractField; +use sp1_recursion_core::air::Block; +use sp1_stark::{ + air::{AirInteraction, BaseAirBuilder, MachineAirBuilder}, + InteractionKind, +}; + +use crate::*; + +/// A trait which contains all helper methods for building SP1 recursion machine AIRs. +pub trait SP1RecursionAirBuilder: MachineAirBuilder + RecursionAirBuilder {} + +impl SP1RecursionAirBuilder for AB {} +impl RecursionAirBuilder for AB {} + +pub trait RecursionAirBuilder: BaseAirBuilder { + fn send_single>( + &mut self, + addr: Address, + val: E, + mult: impl Into, + ) { + let mut padded_value = core::array::from_fn(|_| Self::Expr::zero()); + padded_value[0] = val.into(); + self.send_block(Address(addr.0.into()), Block(padded_value), mult) + } + + fn send_block>( + &mut self, + addr: Address, + val: Block, + mult: impl Into, + ) { + self.send(AirInteraction::new( + once(addr.0).chain(val).map(Into::into).collect(), + mult.into(), + InteractionKind::Memory, + )); + } + + fn receive_single>( + &mut self, + addr: Address, + val: E, + mult: impl Into, + ) { + let mut padded_value = core::array::from_fn(|_| Self::Expr::zero()); + padded_value[0] = val.into(); + self.receive_block(Address(addr.0.into()), Block(padded_value), mult) + } + + fn receive_block>( + &mut self, + addr: Address, + val: Block, + mult: impl Into, + ) { + self.receive(AirInteraction::new( + once(addr.0).chain(val).map(Into::into).collect(), + mult.into(), + InteractionKind::Memory, + )); + } +} diff --git a/crates/recursion/core-v2/src/chips/alu_base.rs b/crates/recursion/core-v2/src/chips/alu_base.rs new file mode 100644 index 0000000000..ccce0581ed --- /dev/null +++ b/crates/recursion/core-v2/src/chips/alu_base.rs @@ -0,0 +1,242 @@ +use core::borrow::Borrow; +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; +use p3_field::{Field, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::*; +use sp1_core_machine::utils::next_power_of_two; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::MachineAir; +use std::{borrow::BorrowMut, iter::zip}; + +use crate::{builder::SP1RecursionAirBuilder, *}; + +pub const NUM_BASE_ALU_ENTRIES_PER_ROW: usize = 8; + +#[derive(Default)] +pub struct BaseAluChip {} + +pub const NUM_BASE_ALU_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct BaseAluCols { + pub values: [BaseAluValueCols; NUM_BASE_ALU_ENTRIES_PER_ROW], +} + +pub const NUM_BASE_ALU_VALUE_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct BaseAluValueCols { + pub vals: BaseAluIo, +} + +pub const NUM_BASE_ALU_PREPROCESSED_COLS: usize = + core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct BaseAluPreprocessedCols { + pub accesses: [BaseAluAccessCols; NUM_BASE_ALU_ENTRIES_PER_ROW], +} + +pub const NUM_BASE_ALU_ACCESS_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct BaseAluAccessCols { + pub addrs: BaseAluIo>, + pub is_add: F, + pub is_sub: F, + pub is_mul: F, + pub is_div: F, + pub mult: F, +} + +impl BaseAir for BaseAluChip { + fn width(&self) -> usize { + NUM_BASE_ALU_COLS + } +} + +impl MachineAir for BaseAluChip { + type Record = ExecutionRecord; + + type Program = crate::RecursionProgram; + + fn name(&self) -> String { + "BaseAlu".to_string() + } + + fn preprocessed_width(&self) -> usize { + NUM_BASE_ALU_PREPROCESSED_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + // Allocating an intermediate `Vec` is faster. + let instrs = program + .instructions + .iter() // Faster than using `rayon` for some reason. Maybe vectorization? + .filter_map(|instruction| match instruction { + Instruction::BaseAlu(x) => Some(x), + _ => None, + }) + .collect::>(); + + let nb_rows = instrs.len().div_ceil(NUM_BASE_ALU_ENTRIES_PER_ROW); + let padded_nb_rows = next_power_of_two(nb_rows, None); + let mut values = vec![F::zero(); padded_nb_rows * NUM_BASE_ALU_PREPROCESSED_COLS]; + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let populate_len = instrs.len() * NUM_BASE_ALU_ACCESS_COLS; + values[..populate_len].par_chunks_mut(NUM_BASE_ALU_ACCESS_COLS).zip_eq(instrs).for_each( + |(row, instr)| { + let BaseAluInstr { opcode, mult, addrs } = instr; + let access: &mut BaseAluAccessCols<_> = row.borrow_mut(); + *access = BaseAluAccessCols { + addrs: addrs.to_owned(), + is_add: F::from_bool(false), + is_sub: F::from_bool(false), + is_mul: F::from_bool(false), + is_div: F::from_bool(false), + mult: mult.to_owned(), + }; + let target_flag = match opcode { + BaseAluOpcode::AddF => &mut access.is_add, + BaseAluOpcode::SubF => &mut access.is_sub, + BaseAluOpcode::MulF => &mut access.is_mul, + BaseAluOpcode::DivF => &mut access.is_div, + }; + *target_flag = F::from_bool(true); + }, + ); + + // Convert the trace to a row major matrix. + Some(RowMajorMatrix::new(values, NUM_BASE_ALU_PREPROCESSED_COLS)) + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn generate_trace(&self, input: &Self::Record, _: &mut Self::Record) -> RowMajorMatrix { + let events = &input.base_alu_events; + let nb_rows = events.len().div_ceil(NUM_BASE_ALU_ENTRIES_PER_ROW); + let padded_nb_rows = next_power_of_two(nb_rows, None); + let mut values = vec![F::zero(); padded_nb_rows * NUM_BASE_ALU_COLS]; + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let populate_len = events.len() * NUM_BASE_ALU_VALUE_COLS; + values[..populate_len].par_chunks_mut(NUM_BASE_ALU_VALUE_COLS).zip_eq(events).for_each( + |(row, &vals)| { + let cols: &mut BaseAluValueCols<_> = row.borrow_mut(); + *cols = BaseAluValueCols { vals }; + }, + ); + + // Convert the trace to a row major matrix. + RowMajorMatrix::new(values, NUM_BASE_ALU_COLS) + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl Air for BaseAluChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &BaseAluCols = (*local).borrow(); + let prep = builder.preprocessed(); + let prep_local = prep.row_slice(0); + let prep_local: &BaseAluPreprocessedCols = (*prep_local).borrow(); + + for ( + BaseAluValueCols { vals: BaseAluIo { out, in1, in2 } }, + BaseAluAccessCols { addrs, is_add, is_sub, is_mul, is_div, mult }, + ) in zip(local.values, prep_local.accesses) + { + // Check exactly one flag is enabled. + let is_real = is_add + is_sub + is_mul + is_div; + builder.assert_bool(is_real.clone()); + + builder.when(is_add).assert_eq(in1 + in2, out); + builder.when(is_sub).assert_eq(in1, in2 + out); + builder.when(is_mul).assert_eq(in1 * in2, out); + builder.when(is_div).assert_eq(in1, in2 * out); + + builder.receive_single(addrs.in1, in1, is_real.clone()); + + builder.receive_single(addrs.in2, in2, is_real); + + builder.send_single(addrs.out, out, mult); + } + } +} + +#[cfg(test)] +mod tests { + use machine::tests::run_recursion_test_machines; + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use rand::{rngs::StdRng, Rng, SeedableRng}; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; + + use super::*; + + use crate::runtime::instruction as instr; + + #[test] + fn generate_trace() { + type F = BabyBear; + + let shard = ExecutionRecord { + base_alu_events: vec![BaseAluIo { out: F::one(), in1: F::one(), in2: F::one() }], + ..Default::default() + }; + let chip = BaseAluChip::default(); + let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } + + #[test] + pub fn four_ops() { + type SC = BabyBearPoseidon2; + type F = ::Val; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_felt = move || -> F { rng.sample(rand::distributions::Standard) }; + let mut addr = 0; + + let instructions = (0..1000) + .flat_map(|_| { + let quot = random_felt(); + let in2 = random_felt(); + let in1 = in2 * quot; + let alloc_size = 6; + let a = (0..alloc_size).map(|x| x + addr).collect::>(); + addr += alloc_size; + [ + instr::mem_single(MemAccessKind::Write, 4, a[0], in1), + instr::mem_single(MemAccessKind::Write, 4, a[1], in2), + instr::base_alu(BaseAluOpcode::AddF, 1, a[2], a[0], a[1]), + instr::mem_single(MemAccessKind::Read, 1, a[2], in1 + in2), + instr::base_alu(BaseAluOpcode::SubF, 1, a[3], a[0], a[1]), + instr::mem_single(MemAccessKind::Read, 1, a[3], in1 - in2), + instr::base_alu(BaseAluOpcode::MulF, 1, a[4], a[0], a[1]), + instr::mem_single(MemAccessKind::Read, 1, a[4], in1 * in2), + instr::base_alu(BaseAluOpcode::DivF, 1, a[5], a[0], a[1]), + instr::mem_single(MemAccessKind::Read, 1, a[5], quot), + ] + }) + .collect::>>(); + + let program = RecursionProgram { instructions, ..Default::default() }; + + run_recursion_test_machines(program); + } +} diff --git a/crates/recursion/core-v2/src/chips/alu_ext.rs b/crates/recursion/core-v2/src/chips/alu_ext.rs new file mode 100644 index 0000000000..39a92c7f8a --- /dev/null +++ b/crates/recursion/core-v2/src/chips/alu_ext.rs @@ -0,0 +1,254 @@ +use core::borrow::Borrow; +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::{extension::BinomiallyExtendable, Field, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::*; +use sp1_core_machine::utils::next_power_of_two; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{ExtensionAirBuilder, MachineAir}; +use std::{borrow::BorrowMut, iter::zip}; + +use crate::{builder::SP1RecursionAirBuilder, *}; + +pub const NUM_EXT_ALU_ENTRIES_PER_ROW: usize = 4; + +#[derive(Default)] +pub struct ExtAluChip {} + +pub const NUM_EXT_ALU_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct ExtAluCols { + pub values: [ExtAluValueCols; NUM_EXT_ALU_ENTRIES_PER_ROW], +} +const NUM_EXT_ALU_VALUE_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct ExtAluValueCols { + pub vals: ExtAluIo>, +} + +pub const NUM_EXT_ALU_PREPROCESSED_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct ExtAluPreprocessedCols { + pub accesses: [ExtAluAccessCols; NUM_EXT_ALU_ENTRIES_PER_ROW], +} + +pub const NUM_EXT_ALU_ACCESS_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct ExtAluAccessCols { + pub addrs: ExtAluIo>, + pub is_add: F, + pub is_sub: F, + pub is_mul: F, + pub is_div: F, + pub mult: F, +} + +impl BaseAir for ExtAluChip { + fn width(&self) -> usize { + NUM_EXT_ALU_COLS + } +} + +impl> MachineAir for ExtAluChip { + type Record = ExecutionRecord; + + type Program = crate::RecursionProgram; + + fn name(&self) -> String { + "ExtAlu".to_string() + } + + fn preprocessed_width(&self) -> usize { + NUM_EXT_ALU_PREPROCESSED_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + // Allocating an intermediate `Vec` is faster. + let instrs = program + .instructions + .iter() // Faster than using `rayon` for some reason. Maybe vectorization? + .filter_map(|instruction| match instruction { + Instruction::ExtAlu(x) => Some(x), + _ => None, + }) + .collect::>(); + + let nb_rows = instrs.len().div_ceil(NUM_EXT_ALU_ENTRIES_PER_ROW); + let padded_nb_rows = next_power_of_two(nb_rows, None); + let mut values = vec![F::zero(); padded_nb_rows * NUM_EXT_ALU_PREPROCESSED_COLS]; + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let populate_len = instrs.len() * NUM_EXT_ALU_ACCESS_COLS; + values[..populate_len].par_chunks_mut(NUM_EXT_ALU_ACCESS_COLS).zip_eq(instrs).for_each( + |(row, instr)| { + let ExtAluInstr { opcode, mult, addrs } = instr; + let access: &mut ExtAluAccessCols<_> = row.borrow_mut(); + *access = ExtAluAccessCols { + addrs: addrs.to_owned(), + is_add: F::from_bool(false), + is_sub: F::from_bool(false), + is_mul: F::from_bool(false), + is_div: F::from_bool(false), + mult: mult.to_owned(), + }; + let target_flag = match opcode { + ExtAluOpcode::AddE => &mut access.is_add, + ExtAluOpcode::SubE => &mut access.is_sub, + ExtAluOpcode::MulE => &mut access.is_mul, + ExtAluOpcode::DivE => &mut access.is_div, + }; + *target_flag = F::from_bool(true); + }, + ); + + // Convert the trace to a row major matrix. + Some(RowMajorMatrix::new(values, NUM_EXT_ALU_PREPROCESSED_COLS)) + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn generate_trace(&self, input: &Self::Record, _: &mut Self::Record) -> RowMajorMatrix { + let events = &input.ext_alu_events; + let nb_rows = events.len().div_ceil(NUM_EXT_ALU_ENTRIES_PER_ROW); + let padded_nb_rows = next_power_of_two(nb_rows, None); + let mut values = vec![F::zero(); padded_nb_rows * NUM_EXT_ALU_COLS]; + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let populate_len = events.len() * NUM_EXT_ALU_VALUE_COLS; + values[..populate_len].par_chunks_mut(NUM_EXT_ALU_VALUE_COLS).zip_eq(events).for_each( + |(row, &vals)| { + let cols: &mut ExtAluValueCols<_> = row.borrow_mut(); + *cols = ExtAluValueCols { vals }; + }, + ); + + // Convert the trace to a row major matrix. + RowMajorMatrix::new(values, NUM_EXT_ALU_COLS) + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl Air for ExtAluChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &ExtAluCols = (*local).borrow(); + let prep = builder.preprocessed(); + let prep_local = prep.row_slice(0); + let prep_local: &ExtAluPreprocessedCols = (*prep_local).borrow(); + + for ( + ExtAluValueCols { vals }, + ExtAluAccessCols { addrs, is_add, is_sub, is_mul, is_div, mult }, + ) in zip(local.values, prep_local.accesses) + { + let in1 = vals.in1.as_extension::(); + let in2 = vals.in2.as_extension::(); + let out = vals.out.as_extension::(); + + // Check exactly one flag is enabled. + let is_real = is_add + is_sub + is_mul + is_div; + builder.assert_bool(is_real.clone()); + + builder.when(is_add).assert_ext_eq(in1.clone() + in2.clone(), out.clone()); + builder.when(is_sub).assert_ext_eq(in1.clone(), in2.clone() + out.clone()); + builder.when(is_mul).assert_ext_eq(in1.clone() * in2.clone(), out.clone()); + builder.when(is_div).assert_ext_eq(in1, in2 * out); + + // Read the inputs from memory. + builder.receive_block(addrs.in1, vals.in1, is_real.clone()); + + builder.receive_block(addrs.in2, vals.in2, is_real); + + // Write the output to memory. + builder.send_block(addrs.out, vals.out, mult); + } + } +} + +#[cfg(test)] +mod tests { + use machine::tests::run_recursion_test_machines; + use p3_baby_bear::BabyBear; + use p3_field::{extension::BinomialExtensionField, AbstractExtensionField, AbstractField}; + use p3_matrix::dense::RowMajorMatrix; + + use rand::{rngs::StdRng, Rng, SeedableRng}; + use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; + use sp1_stark::StarkGenericConfig; + + use super::*; + + use crate::runtime::instruction as instr; + + #[test] + fn generate_trace() { + type F = BabyBear; + + let shard = ExecutionRecord { + ext_alu_events: vec![ExtAluIo { + out: F::one().into(), + in1: F::one().into(), + in2: F::one().into(), + }], + ..Default::default() + }; + let chip = ExtAluChip::default(); + let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } + + #[test] + pub fn four_ops() { + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_extfelt = move || { + let inner: [F; 4] = core::array::from_fn(|_| rng.sample(rand::distributions::Standard)); + BinomialExtensionField::::from_base_slice(&inner) + }; + let mut addr = 0; + + let instructions = (0..1000) + .flat_map(|_| { + let quot = random_extfelt(); + let in2 = random_extfelt(); + let in1 = in2 * quot; + let alloc_size = 6; + let a = (0..alloc_size).map(|x| x + addr).collect::>(); + addr += alloc_size; + [ + instr::mem_ext(MemAccessKind::Write, 4, a[0], in1), + instr::mem_ext(MemAccessKind::Write, 4, a[1], in2), + instr::ext_alu(ExtAluOpcode::AddE, 1, a[2], a[0], a[1]), + instr::mem_ext(MemAccessKind::Read, 1, a[2], in1 + in2), + instr::ext_alu(ExtAluOpcode::SubE, 1, a[3], a[0], a[1]), + instr::mem_ext(MemAccessKind::Read, 1, a[3], in1 - in2), + instr::ext_alu(ExtAluOpcode::MulE, 1, a[4], a[0], a[1]), + instr::mem_ext(MemAccessKind::Read, 1, a[4], in1 * in2), + instr::ext_alu(ExtAluOpcode::DivE, 1, a[5], a[0], a[1]), + instr::mem_ext(MemAccessKind::Read, 1, a[5], quot), + ] + }) + .collect::>>(); + + let program = RecursionProgram { instructions, ..Default::default() }; + + run_recursion_test_machines(program); + } +} diff --git a/crates/recursion/core-v2/src/chips/dummy.rs b/crates/recursion/core-v2/src/chips/dummy.rs new file mode 100644 index 0000000000..f903cf5759 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/dummy.rs @@ -0,0 +1,78 @@ +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::{Field, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::MachineAir; + +use crate::{builder::SP1RecursionAirBuilder, *}; + +/// A dummy chip with 1<< `log_height` rows, `COL_PADDING` main columns, `COL_PADDING` preprocessed +/// columns, and no constraints. +pub struct DummyChip { + log_height: usize, +} + +impl Default for DummyChip { + fn default() -> Self { + Self { log_height: 1 } + } +} + +impl DummyChip { + pub fn new(log_height: usize) -> Self { + Self { log_height } + } +} + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct DummyCols { + pub vals: [F; COL_PADDING], +} + +impl BaseAir for DummyChip { + fn width(&self) -> usize { + COL_PADDING + } +} + +impl MachineAir for DummyChip { + type Record = ExecutionRecord; + + type Program = crate::RecursionProgram; + + fn name(&self) -> String { + "DummyWide".to_string() + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn generate_trace(&self, _: &Self::Record, _: &mut Self::Record) -> RowMajorMatrix { + RowMajorMatrix::new(vec![F::zero(); COL_PADDING * (1 << self.log_height)], COL_PADDING) + } + + fn generate_preprocessed_trace(&self, _program: &Self::Program) -> Option> { + Some(RowMajorMatrix::new(vec![F::zero(); 1 << self.log_height], 1)) + } + + fn preprocessed_width(&self) -> usize { + 1 + } + + fn included(&self, _record: &Self::Record) -> bool { + COL_PADDING != 0 + } +} + +impl Air for DummyChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + builder.assert_zero(local[0]); + } +} diff --git a/crates/recursion/core-v2/src/chips/exp_reverse_bits.rs b/crates/recursion/core-v2/src/chips/exp_reverse_bits.rs new file mode 100644 index 0000000000..0cbfeaa982 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/exp_reverse_bits.rs @@ -0,0 +1,401 @@ +#![allow(clippy::needless_range_loop)] + +use core::borrow::Borrow; +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_rows_fixed; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, ExtensionAirBuilder, MachineAir, SP1AirBuilder}; +use std::borrow::BorrowMut; +use tracing::instrument; + +use crate::{ + builder::SP1RecursionAirBuilder, + runtime::{ExecutionRecord, RecursionProgram}, + ExpReverseBitsInstr, Instruction, +}; + +use super::mem::MemoryAccessCols; + +pub const NUM_EXP_REVERSE_BITS_LEN_COLS: usize = core::mem::size_of::>(); +pub const NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS: usize = + core::mem::size_of::>(); + +pub struct ExpReverseBitsLenChip { + pub fixed_log2_rows: Option, + pub pad: bool, +} +impl Default for ExpReverseBitsLenChip { + fn default() -> Self { + Self { fixed_log2_rows: None, pad: true } + } +} + +#[derive(AlignedBorrow, Clone, Copy, Debug)] +#[repr(C)] +pub struct ExpReverseBitsLenPreprocessedCols { + pub x_mem: MemoryAccessCols, + pub exponent_mem: MemoryAccessCols, + pub result_mem: MemoryAccessCols, + pub iteration_num: T, + pub is_first: T, + pub is_last: T, + pub is_real: T, +} + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct ExpReverseBitsLenCols { + /// The base of the exponentiation. + pub x: T, + + /// The current bit of the exponent. This is read from memory. + pub current_bit: T, + + /// The previous accumulator squared. + pub prev_accum_squared: T, + + /// Is set to the value local.prev_accum_squared * local.multiplier. + pub prev_accum_squared_times_multiplier: T, + + /// The accumulator of the current iteration. + pub accum: T, + + /// The accumulator squared. + pub accum_squared: T, + + /// A column which equals x if `current_bit` is on, and 1 otherwise. + pub multiplier: T, +} + +impl BaseAir for ExpReverseBitsLenChip { + fn width(&self) -> usize { + NUM_EXP_REVERSE_BITS_LEN_COLS + } +} + +impl MachineAir for ExpReverseBitsLenChip { + type Record = ExecutionRecord; + + type Program = RecursionProgram; + + fn name(&self) -> String { + "ExpReverseBitsLen".to_string() + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn preprocessed_width(&self) -> usize { + NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + let mut rows: Vec<[F; NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS]> = Vec::new(); + program + .instructions + .iter() + .filter_map(|instruction| { + if let Instruction::ExpReverseBitsLen(instr) = instruction { + Some(instr) + } else { + None + } + }) + .for_each(|instruction| { + let ExpReverseBitsInstr { addrs, mult } = instruction; + let mut row_add = + vec![[F::zero(); NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS]; addrs.exp.len()]; + row_add.iter_mut().enumerate().for_each(|(i, row)| { + let row: &mut ExpReverseBitsLenPreprocessedCols = + row.as_mut_slice().borrow_mut(); + row.iteration_num = F::from_canonical_u32(i as u32); + row.is_first = F::from_bool(i == 0); + row.is_last = F::from_bool(i == addrs.exp.len() - 1); + row.is_real = F::one(); + row.x_mem = MemoryAccessCols { addr: addrs.base, mult: -F::from_bool(i == 0) }; + row.exponent_mem = MemoryAccessCols { addr: addrs.exp[i], mult: F::neg_one() }; + row.result_mem = MemoryAccessCols { + addr: addrs.result, + mult: *mult * F::from_bool(i == addrs.exp.len() - 1), + }; + }); + rows.extend(row_add); + }); + + // Pad the trace to a power of two. + if self.pad { + pad_rows_fixed( + &mut rows, + || [F::zero(); NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS], + self.fixed_log2_rows, + ); + } + + let trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect(), + NUM_EXP_REVERSE_BITS_LEN_PREPROCESSED_COLS, + ); + Some(trace) + } + + #[instrument(name = "generate exp reverse bits len trace", level = "debug", skip_all, fields(rows = input.exp_reverse_bits_len_events.len()))] + fn generate_trace( + &self, + input: &ExecutionRecord, + _: &mut ExecutionRecord, + ) -> RowMajorMatrix { + let mut overall_rows = Vec::new(); + input.exp_reverse_bits_len_events.iter().for_each(|event| { + let mut rows = vec![vec![F::zero(); NUM_EXP_REVERSE_BITS_LEN_COLS]; event.exp.len()]; + + let mut accum = F::one(); + + rows.iter_mut().enumerate().for_each(|(i, row)| { + let cols: &mut ExpReverseBitsLenCols = row.as_mut_slice().borrow_mut(); + + let prev_accum = accum; + accum = prev_accum + * prev_accum + * if event.exp[i] == F::one() { event.base } else { F::one() }; + + cols.x = event.base; + cols.current_bit = event.exp[i]; + cols.accum = accum; + cols.accum_squared = accum * accum; + cols.prev_accum_squared = prev_accum * prev_accum; + cols.multiplier = if event.exp[i] == F::one() { event.base } else { F::one() }; + cols.prev_accum_squared_times_multiplier = + cols.prev_accum_squared * cols.multiplier; + if i == event.exp.len() { + assert_eq!(event.result, accum); + } + }); + + overall_rows.extend(rows); + }); + + // Pad the trace to a power of two. + if self.pad { + pad_rows_fixed( + &mut overall_rows, + || [F::zero(); NUM_EXP_REVERSE_BITS_LEN_COLS].to_vec(), + self.fixed_log2_rows, + ); + } + + // Convert the trace to a row major matrix. + let trace = RowMajorMatrix::new( + overall_rows.into_iter().flatten().collect(), + NUM_EXP_REVERSE_BITS_LEN_COLS, + ); + + #[cfg(debug_assertions)] + println!( + "exp reverse bits len trace dims is width: {:?}, height: {:?}", + trace.width(), + trace.height() + ); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl ExpReverseBitsLenChip { + pub fn eval_exp_reverse_bits_len< + AB: BaseAirBuilder + ExtensionAirBuilder + SP1RecursionAirBuilder + SP1AirBuilder, + >( + &self, + builder: &mut AB, + local: &ExpReverseBitsLenCols, + local_prepr: &ExpReverseBitsLenPreprocessedCols, + next: &ExpReverseBitsLenCols, + next_prepr: &ExpReverseBitsLenPreprocessedCols, + ) { + // Dummy constraints to normalize to DEGREE when DEGREE > 3. + if DEGREE > 3 { + let lhs = (0..DEGREE).map(|_| local_prepr.is_real.into()).product::(); + let rhs = (0..DEGREE).map(|_| local_prepr.is_real.into()).product::(); + builder.assert_eq(lhs, rhs); + } + + // Constrain mem read for x. The read mult is one for only the first row, and zero for all + // others. + builder.send_single(local_prepr.x_mem.addr, local.x, local_prepr.x_mem.mult); + + // Ensure that the value at the x memory access is unchanged when not `is_last`. + builder + .when_transition() + .when(next_prepr.is_real) + .when_not(local_prepr.is_last) + .assert_eq(local.x, next.x); + + // Constrain mem read for exponent's bits. The read mult is one for all real rows. + builder.send_single( + local_prepr.exponent_mem.addr, + local.current_bit, + local_prepr.exponent_mem.mult, + ); + + // The accumulator needs to start with the multiplier for every `is_first` row. + builder.when(local_prepr.is_first).assert_eq(local.accum, local.multiplier); + + // `multiplier` is x if the current bit is 1, and 1 if the current bit is 0. + builder + .when(local_prepr.is_real) + .when(local.current_bit) + .assert_eq(local.multiplier, local.x); + builder + .when(local_prepr.is_real) + .when_not(local.current_bit) + .assert_eq(local.multiplier, AB::Expr::one()); + + // To get `next.accum`, we multiply `local.prev_accum_squared` by `local.multiplier` when + // not `is_last`. + builder.when(local_prepr.is_real).assert_eq( + local.prev_accum_squared_times_multiplier, + local.prev_accum_squared * local.multiplier, + ); + + builder + .when(local_prepr.is_real) + .when_not(local_prepr.is_last) + .assert_eq(local.accum, local.prev_accum_squared_times_multiplier); + + // Constrain the accum_squared column. + builder.when(local_prepr.is_real).assert_eq(local.accum_squared, local.accum * local.accum); + + builder + .when_transition() + .when(next_prepr.is_real) + .when_not(local_prepr.is_last) + .assert_eq(next.prev_accum_squared, local.accum_squared); + + // Constrain mem write for the result. + builder.send_single(local_prepr.result_mem.addr, local.accum, local_prepr.result_mem.mult); + } + + pub const fn do_exp_bit_memory_access( + local: &ExpReverseBitsLenPreprocessedCols, + ) -> T { + local.is_real + } +} + +impl Air for ExpReverseBitsLenChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let (local, next) = (main.row_slice(0), main.row_slice(1)); + let local: &ExpReverseBitsLenCols = (*local).borrow(); + let next: &ExpReverseBitsLenCols = (*next).borrow(); + let prep = builder.preprocessed(); + let (prep_local, prep_next) = (prep.row_slice(0), prep.row_slice(1)); + let prep_local: &ExpReverseBitsLenPreprocessedCols<_> = (*prep_local).borrow(); + let prep_next: &ExpReverseBitsLenPreprocessedCols<_> = (*prep_next).borrow(); + self.eval_exp_reverse_bits_len::(builder, local, prep_local, next, prep_next); + } +} + +#[cfg(test)] +mod tests { + use itertools::Itertools; + use p3_util::reverse_bits_len; + use rand::{rngs::StdRng, Rng, SeedableRng}; + use sp1_core_machine::utils::setup_logger; + use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; + use sp1_stark::{air::MachineAir, StarkGenericConfig}; + use std::iter::once; + + use p3_baby_bear::BabyBear; + use p3_field::{AbstractField, PrimeField32}; + use p3_matrix::dense::RowMajorMatrix; + + use crate::{ + chips::exp_reverse_bits::ExpReverseBitsLenChip, + machine::tests::run_recursion_test_machines, + runtime::{instruction as instr, ExecutionRecord}, + ExpReverseBitsEvent, Instruction, MemAccessKind, RecursionProgram, + }; + + #[test] + fn prove_babybear_circuit_erbl() { + setup_logger(); + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_felt = move || -> F { F::from_canonical_u32(rng.gen_range(0..1 << 16)) }; + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_bit = move || rng.gen_range(0..2); + let mut addr = 0; + + let instructions = (1..15) + .flat_map(|i| { + let base = random_felt(); + let exponent_bits = vec![random_bit(); i]; + let exponent = F::from_canonical_u32( + exponent_bits.iter().enumerate().fold(0, |acc, (i, x)| acc + x * (1 << i)), + ); + let result = + base.exp_u64(reverse_bits_len(exponent.as_canonical_u32() as usize, i) as u64); + + let alloc_size = i + 2; + let exp_a = (0..i).map(|x| x + addr + 1).collect::>(); + let exp_a_clone = exp_a.clone(); + let x_a = addr; + let result_a = addr + alloc_size - 1; + addr += alloc_size; + let exp_bit_instructions = (0..i).map(move |j| { + instr::mem_single( + MemAccessKind::Write, + 1, + exp_a_clone[j] as u32, + F::from_canonical_u32(exponent_bits[j]), + ) + }); + once(instr::mem_single(MemAccessKind::Write, 1, x_a as u32, base)) + .chain(exp_bit_instructions) + .chain(once(instr::exp_reverse_bits_len( + 1, + F::from_canonical_u32(x_a as u32), + exp_a + .into_iter() + .map(|bit| F::from_canonical_u32(bit as u32)) + .collect_vec(), + F::from_canonical_u32(result_a as u32), + ))) + .chain(once(instr::mem_single(MemAccessKind::Read, 1, result_a as u32, result))) + }) + .collect::>>(); + + let program = RecursionProgram { instructions, ..Default::default() }; + + run_recursion_test_machines(program); + } + + #[test] + fn generate_erbl_circuit_trace() { + type F = BabyBear; + + let shard = ExecutionRecord { + exp_reverse_bits_len_events: vec![ExpReverseBitsEvent { + base: F::two(), + exp: vec![F::zero(), F::one(), F::one()], + result: F::two().exp_u64(0b110), + }], + ..Default::default() + }; + let chip = ExpReverseBitsLenChip::<3>::default(); + let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } +} diff --git a/crates/recursion/core-v2/src/chips/fri_fold.rs b/crates/recursion/core-v2/src/chips/fri_fold.rs new file mode 100644 index 0000000000..875fce491b --- /dev/null +++ b/crates/recursion/core-v2/src/chips/fri_fold.rs @@ -0,0 +1,547 @@ +#![allow(clippy::needless_range_loop)] + +use core::borrow::Borrow; +use itertools::Itertools; +use sp1_core_machine::utils::pad_rows_fixed; +use sp1_stark::air::{BinomialExtension, MachineAir}; +use std::borrow::BorrowMut; +use tracing::instrument; + +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; +use p3_field::PrimeField32; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_stark::air::{BaseAirBuilder, ExtensionAirBuilder}; + +use sp1_derive::AlignedBorrow; +use sp1_recursion_core::air::Block; + +use crate::{ + builder::SP1RecursionAirBuilder, + runtime::{Instruction, RecursionProgram}, + ExecutionRecord, FriFoldInstr, +}; + +use super::mem::MemoryAccessCols; + +pub const NUM_FRI_FOLD_COLS: usize = core::mem::size_of::>(); +pub const NUM_FRI_FOLD_PREPROCESSED_COLS: usize = + core::mem::size_of::>(); + +pub struct FriFoldChip { + pub fixed_log2_rows: Option, + pub pad: bool, +} + +impl Default for FriFoldChip { + fn default() -> Self { + Self { fixed_log2_rows: None, pad: true } + } +} + +/// The preprocessed columns for a FRI fold invocation. +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct FriFoldPreprocessedCols { + pub is_first: T, + + // Memory accesses for the single fields. + pub z_mem: MemoryAccessCols, + pub alpha_mem: MemoryAccessCols, + pub x_mem: MemoryAccessCols, + + // Memory accesses for the vector field inputs. + pub alpha_pow_input_mem: MemoryAccessCols, + pub ro_input_mem: MemoryAccessCols, + pub p_at_x_mem: MemoryAccessCols, + pub p_at_z_mem: MemoryAccessCols, + + // Memory accesses for the vector field outputs. + pub ro_output_mem: MemoryAccessCols, + pub alpha_pow_output_mem: MemoryAccessCols, + + pub is_real: T, +} + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct FriFoldCols { + pub z: Block, + pub alpha: Block, + pub x: T, + + pub p_at_x: Block, + pub p_at_z: Block, + pub alpha_pow_input: Block, + pub ro_input: Block, + + pub alpha_pow_output: Block, + pub ro_output: Block, +} + +impl BaseAir for FriFoldChip { + fn width(&self) -> usize { + NUM_FRI_FOLD_COLS + } +} + +impl MachineAir for FriFoldChip { + type Record = ExecutionRecord; + + type Program = RecursionProgram; + + fn name(&self) -> String { + "FriFold".to_string() + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn preprocessed_width(&self) -> usize { + NUM_FRI_FOLD_PREPROCESSED_COLS + } + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + let mut rows: Vec<[F; NUM_FRI_FOLD_PREPROCESSED_COLS]> = Vec::new(); + program + .instructions + .iter() + .filter_map(|instruction| { + if let Instruction::FriFold(instr) = instruction { + Some(instr) + } else { + None + } + }) + .for_each(|instruction| { + let FriFoldInstr { + base_single_addrs, + ext_single_addrs, + ext_vec_addrs, + alpha_pow_mults, + ro_mults, + } = instruction.as_ref(); + let mut row_add = + vec![[F::zero(); NUM_FRI_FOLD_PREPROCESSED_COLS]; ext_vec_addrs.ps_at_z.len()]; + + row_add.iter_mut().enumerate().for_each(|(i, row)| { + let row: &mut FriFoldPreprocessedCols = row.as_mut_slice().borrow_mut(); + row.is_first = F::from_bool(i == 0); + + // Only need to read z, x, and alpha on the first iteration, hence the + // multiplicities are i==0. + row.z_mem = + MemoryAccessCols { addr: ext_single_addrs.z, mult: -F::from_bool(i == 0) }; + row.x_mem = + MemoryAccessCols { addr: base_single_addrs.x, mult: -F::from_bool(i == 0) }; + row.alpha_mem = MemoryAccessCols { + addr: ext_single_addrs.alpha, + mult: -F::from_bool(i == 0), + }; + + // Read the memory for the input vectors. + row.alpha_pow_input_mem = MemoryAccessCols { + addr: ext_vec_addrs.alpha_pow_input[i], + mult: F::neg_one(), + }; + row.ro_input_mem = + MemoryAccessCols { addr: ext_vec_addrs.ro_input[i], mult: F::neg_one() }; + row.p_at_z_mem = + MemoryAccessCols { addr: ext_vec_addrs.ps_at_z[i], mult: F::neg_one() }; + row.p_at_x_mem = + MemoryAccessCols { addr: ext_vec_addrs.mat_opening[i], mult: F::neg_one() }; + + // Write the memory for the output vectors. + row.alpha_pow_output_mem = MemoryAccessCols { + addr: ext_vec_addrs.alpha_pow_output[i], + mult: alpha_pow_mults[i], + }; + row.ro_output_mem = + MemoryAccessCols { addr: ext_vec_addrs.ro_output[i], mult: ro_mults[i] }; + + row.is_real = F::one(); + }); + rows.extend(row_add); + }); + + // Pad the trace to a power of two. + if self.pad { + pad_rows_fixed( + &mut rows, + || [F::zero(); NUM_FRI_FOLD_PREPROCESSED_COLS], + self.fixed_log2_rows, + ); + } + + let trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect(), + NUM_FRI_FOLD_PREPROCESSED_COLS, + ); + Some(trace) + } + + #[instrument(name = "generate fri fold trace", level = "debug", skip_all, fields(rows = input.fri_fold_events.len()))] + fn generate_trace( + &self, + input: &ExecutionRecord, + _: &mut ExecutionRecord, + ) -> RowMajorMatrix { + let mut rows = input + .fri_fold_events + .iter() + .map(|event| { + let mut row = [F::zero(); NUM_FRI_FOLD_COLS]; + + let cols: &mut FriFoldCols = row.as_mut_slice().borrow_mut(); + + cols.x = event.base_single.x; + cols.z = event.ext_single.z; + cols.alpha = event.ext_single.alpha; + + cols.p_at_z = event.ext_vec.ps_at_z; + cols.p_at_x = event.ext_vec.mat_opening; + cols.alpha_pow_input = event.ext_vec.alpha_pow_input; + cols.ro_input = event.ext_vec.ro_input; + + cols.alpha_pow_output = event.ext_vec.alpha_pow_output; + cols.ro_output = event.ext_vec.ro_output; + + row + }) + .collect_vec(); + + // Pad the trace to a power of two. + if self.pad { + pad_rows_fixed(&mut rows, || [F::zero(); NUM_FRI_FOLD_COLS], self.fixed_log2_rows); + } + + // Convert the trace to a row major matrix. + let trace = RowMajorMatrix::new(rows.into_iter().flatten().collect(), NUM_FRI_FOLD_COLS); + + #[cfg(debug_assertions)] + println!("fri fold trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl FriFoldChip { + pub fn eval_fri_fold( + &self, + builder: &mut AB, + local: &FriFoldCols, + next: &FriFoldCols, + local_prepr: &FriFoldPreprocessedCols, + next_prepr: &FriFoldPreprocessedCols, + ) { + // Constrain mem read for x. Read at the first fri fold row. + builder.send_single(local_prepr.x_mem.addr, local.x, local_prepr.x_mem.mult); + + // Ensure that the x value is the same for all rows within a fri fold invocation. + builder + .when_transition() + .when(next_prepr.is_real) + .when_not(next_prepr.is_first) + .assert_eq(local.x, next.x); + + // Constrain mem read for z. Read at the first fri fold row. + builder.send_block(local_prepr.z_mem.addr, local.z, local_prepr.z_mem.mult); + + // Ensure that the z value is the same for all rows within a fri fold invocation. + builder + .when_transition() + .when(next_prepr.is_real) + .when_not(next_prepr.is_first) + .assert_ext_eq(local.z.as_extension::(), next.z.as_extension::()); + + // Constrain mem read for alpha. Read at the first fri fold row. + builder.send_block(local_prepr.alpha_mem.addr, local.alpha, local_prepr.alpha_mem.mult); + + // Ensure that the alpha value is the same for all rows within a fri fold invocation. + builder + .when_transition() + .when(next_prepr.is_real) + .when_not(next_prepr.is_first) + .assert_ext_eq(local.alpha.as_extension::(), next.alpha.as_extension::()); + + // Constrain read for alpha_pow_input. + builder.send_block( + local_prepr.alpha_pow_input_mem.addr, + local.alpha_pow_input, + local_prepr.alpha_pow_input_mem.mult, + ); + + // Constrain read for ro_input. + builder.send_block( + local_prepr.ro_input_mem.addr, + local.ro_input, + local_prepr.ro_input_mem.mult, + ); + + // Constrain read for p_at_z. + builder.send_block(local_prepr.p_at_z_mem.addr, local.p_at_z, local_prepr.p_at_z_mem.mult); + + // Constrain read for p_at_x. + builder.send_block(local_prepr.p_at_x_mem.addr, local.p_at_x, local_prepr.p_at_x_mem.mult); + + // Constrain write for alpha_pow_output. + builder.send_block( + local_prepr.alpha_pow_output_mem.addr, + local.alpha_pow_output, + local_prepr.alpha_pow_output_mem.mult, + ); + + // Constrain write for ro_output. + builder.send_block( + local_prepr.ro_output_mem.addr, + local.ro_output, + local_prepr.ro_output_mem.mult, + ); + + // 1. Constrain new_value = old_value * alpha. + let alpha = local.alpha.as_extension::(); + let old_alpha_pow = local.alpha_pow_input.as_extension::(); + let new_alpha_pow = local.alpha_pow_output.as_extension::(); + builder.assert_ext_eq(old_alpha_pow.clone() * alpha, new_alpha_pow.clone()); + + // 2. Constrain new_value = old_alpha_pow * quotient + old_ro, + // where quotient = (p_at_x - p_at_z) / (x - z) + // <=> (new_ro - old_ro) * (z - x) = old_alpha_pow * (p_at_x - p_at_z) + let p_at_z = local.p_at_z.as_extension::(); + let p_at_x = local.p_at_x.as_extension::(); + let z = local.z.as_extension::(); + let x = local.x.into(); + let old_ro = local.ro_input.as_extension::(); + let new_ro = local.ro_output.as_extension::(); + builder.assert_ext_eq( + (new_ro.clone() - old_ro) * (BinomialExtension::from_base(x) - z), + (p_at_x - p_at_z) * old_alpha_pow, + ); + } + + pub const fn do_memory_access(local: &FriFoldPreprocessedCols) -> T { + local.is_real + } +} + +impl Air for FriFoldChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let (local, next) = (main.row_slice(0), main.row_slice(1)); + let local: &FriFoldCols = (*local).borrow(); + let next: &FriFoldCols = (*next).borrow(); + let prepr = builder.preprocessed(); + let (prepr_local, prepr_next) = (prepr.row_slice(0), prepr.row_slice(1)); + let prepr_local: &FriFoldPreprocessedCols = (*prepr_local).borrow(); + let prepr_next: &FriFoldPreprocessedCols = (*prepr_next).borrow(); + + // Dummy constraints to normalize to DEGREE. + let lhs = (0..DEGREE).map(|_| prepr_local.is_real.into()).product::(); + let rhs = (0..DEGREE).map(|_| prepr_local.is_real.into()).product::(); + builder.assert_eq(lhs, rhs); + + self.eval_fri_fold::(builder, local, next, prepr_local, prepr_next); + } +} + +#[cfg(test)] +mod tests { + use p3_field::AbstractExtensionField; + use rand::{rngs::StdRng, Rng, SeedableRng}; + use sp1_core_machine::utils::setup_logger; + use sp1_recursion_core::{air::Block, stark::config::BabyBearPoseidon2Outer}; + use sp1_stark::{air::MachineAir, StarkGenericConfig}; + use std::mem::size_of; + + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use crate::{ + chips::fri_fold::FriFoldChip, + machine::tests::run_recursion_test_machines, + runtime::{instruction as instr, ExecutionRecord}, + FriFoldBaseIo, FriFoldEvent, FriFoldExtSingleIo, FriFoldExtVecIo, Instruction, + MemAccessKind, RecursionProgram, + }; + + #[test] + fn prove_babybear_circuit_fri_fold() { + setup_logger(); + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + type EF = ::Challenge; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_felt = move || -> F { F::from_canonical_u32(rng.gen_range(0..1 << 16)) }; + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_block = + move || Block::from([F::from_canonical_u32(rng.gen_range(0..1 << 16)); 4]); + let mut addr = 0; + + let num_ext_vecs: u32 = size_of::>() as u32; + let num_singles: u32 = + size_of::>() as u32 + size_of::>() as u32; + + let instructions = (2..17) + .flat_map(|i: u32| { + let alloc_size = i * (num_ext_vecs + 2) + num_singles; + + // Allocate the memory for a FRI fold instruction. Here, i is the lengths + // of the vectors for the vector fields of the instruction. + let mat_opening_a = (0..i).map(|x| x + addr).collect::>(); + let ps_at_z_a = (0..i).map(|x| x + i + addr).collect::>(); + + let alpha_pow_input_a = (0..i).map(|x: u32| x + addr + 2 * i).collect::>(); + let ro_input_a = (0..i).map(|x: u32| x + addr + 3 * i).collect::>(); + + let alpha_pow_output_a = (0..i).map(|x: u32| x + addr + 4 * i).collect::>(); + let ro_output_a = (0..i).map(|x: u32| x + addr + 5 * i).collect::>(); + + let x_a = addr + 6 * i; + let z_a = addr + 6 * i + 1; + let alpha_a = addr + 6 * i + 2; + + addr += alloc_size; + + // Generate random values for the inputs. + let x = random_felt(); + let z = random_block(); + let alpha = random_block(); + + let alpha_pow_input = (0..i).map(|_| random_block()).collect::>(); + let ro_input = (0..i).map(|_| random_block()).collect::>(); + + let ps_at_z = (0..i).map(|_| random_block()).collect::>(); + let mat_opening = (0..i).map(|_| random_block()).collect::>(); + + // Compute the outputs from the inputs. + let alpha_pow_output = (0..i) + .map(|i| alpha_pow_input[i as usize].ext::() * alpha.ext::()) + .collect::>(); + let ro_output = (0..i) + .map(|i| { + let i = i as usize; + ro_input[i].ext::() + + alpha_pow_input[i].ext::() + * (-ps_at_z[i].ext::() + mat_opening[i].ext::()) + / (-z.ext::() + x) + }) + .collect::>(); + + // Write the inputs to memory. + let mut instructions = vec![instr::mem_single(MemAccessKind::Write, 1, x_a, x)]; + + instructions.push(instr::mem_block(MemAccessKind::Write, 1, z_a, z)); + + instructions.push(instr::mem_block(MemAccessKind::Write, 1, alpha_a, alpha)); + + (0..i).for_each(|j_32| { + let j = j_32 as usize; + instructions.push(instr::mem_block( + MemAccessKind::Write, + 1, + mat_opening_a[j], + mat_opening[j], + )); + instructions.push(instr::mem_block( + MemAccessKind::Write, + 1, + ps_at_z_a[j], + ps_at_z[j], + )); + + instructions.push(instr::mem_block( + MemAccessKind::Write, + 1, + alpha_pow_input_a[j], + alpha_pow_input[j], + )); + instructions.push(instr::mem_block( + MemAccessKind::Write, + 1, + ro_input_a[j], + ro_input[j], + )); + }); + + // Generate the FRI fold instruction. + instructions.push(instr::fri_fold( + z_a, + alpha_a, + x_a, + mat_opening_a.clone(), + ps_at_z_a.clone(), + alpha_pow_input_a.clone(), + ro_input_a.clone(), + alpha_pow_output_a.clone(), + ro_output_a.clone(), + vec![1; i as usize], + vec![1; i as usize], + )); + + // Read all the outputs. + (0..i).for_each(|j| { + let j = j as usize; + instructions.push(instr::mem_block( + MemAccessKind::Read, + 1, + alpha_pow_output_a[j], + Block::from(alpha_pow_output[j].as_base_slice()), + )); + instructions.push(instr::mem_block( + MemAccessKind::Read, + 1, + ro_output_a[j], + Block::from(ro_output[j].as_base_slice()), + )); + }); + + instructions + }) + .collect::>>(); + + let program = RecursionProgram { instructions, ..Default::default() }; + + run_recursion_test_machines(program); + } + + #[test] + fn generate_fri_fold_circuit_trace() { + type F = BabyBear; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut rng2 = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_felt = move || -> F { F::from_canonical_u32(rng.gen_range(0..1 << 16)) }; + let mut random_block = move || Block::from([random_felt(); 4]); + + let shard = ExecutionRecord { + fri_fold_events: (0..17) + .map(|_| FriFoldEvent { + base_single: FriFoldBaseIo { + x: F::from_canonical_u32(rng2.gen_range(0..1 << 16)), + }, + ext_single: FriFoldExtSingleIo { z: random_block(), alpha: random_block() }, + ext_vec: crate::FriFoldExtVecIo { + mat_opening: random_block(), + ps_at_z: random_block(), + alpha_pow_input: random_block(), + ro_input: random_block(), + alpha_pow_output: random_block(), + ro_output: random_block(), + }, + }) + .collect(), + ..Default::default() + }; + let chip = FriFoldChip::<3>::default(); + let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } +} diff --git a/crates/recursion/core-v2/src/chips/mem/constant.rs b/crates/recursion/core-v2/src/chips/mem/constant.rs new file mode 100644 index 0000000000..1b3654a1e0 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/mem/constant.rs @@ -0,0 +1,241 @@ +use core::borrow::Borrow; +use itertools::Itertools; +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::PrimeField32; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_to_power_of_two; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::MachineAir; +use std::{borrow::BorrowMut, iter::zip, marker::PhantomData}; + +use crate::{builder::SP1RecursionAirBuilder, *}; + +use super::MemoryAccessCols; + +pub const NUM_MEM_ENTRIES_PER_ROW: usize = 16; + +#[derive(Default)] +pub struct MemoryChip { + _data: PhantomData, +} + +pub const NUM_MEM_INIT_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct MemoryCols { + // At least one column is required, otherwise a bunch of things break. + _nothing: F, +} + +pub const NUM_MEM_PREPROCESSED_INIT_COLS: usize = + core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct MemoryPreprocessedCols { + values_and_accesses: [(Block, MemoryAccessCols); NUM_MEM_ENTRIES_PER_ROW], +} +impl BaseAir for MemoryChip { + fn width(&self) -> usize { + NUM_MEM_INIT_COLS + } +} + +impl MachineAir for MemoryChip { + type Record = crate::ExecutionRecord; + + type Program = crate::RecursionProgram; + + fn name(&self) -> String { + "MemoryConst".to_string() + } + fn preprocessed_width(&self) -> usize { + NUM_MEM_PREPROCESSED_INIT_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + let rows = program + .instructions + .iter() + .filter_map(|instruction| match instruction { + Instruction::Mem(MemInstr { addrs, vals, mult, kind }) => { + let mult = mult.to_owned(); + let mult = match kind { + MemAccessKind::Read => -mult, + MemAccessKind::Write => mult, + }; + + Some((vals.inner, MemoryAccessCols { addr: addrs.inner, mult })) + } + _ => None, + }) + .chunks(NUM_MEM_ENTRIES_PER_ROW) + .into_iter() + .map(|row_vs_as| { + let mut row = [F::zero(); NUM_MEM_PREPROCESSED_INIT_COLS]; + let cols: &mut MemoryPreprocessedCols<_> = row.as_mut_slice().borrow_mut(); + for (cell, access) in zip(&mut cols.values_and_accesses, row_vs_as) { + *cell = access; + } + row + }) + .collect::>(); + + // Convert the trace to a row major matrix. + let mut trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect::>(), + NUM_MEM_PREPROCESSED_INIT_COLS, + ); + + // Pad the trace to a power of two. + pad_to_power_of_two::(&mut trace.values); + + Some(trace) + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn generate_trace(&self, input: &Self::Record, _: &mut Self::Record) -> RowMajorMatrix { + // Match number of rows generated by the `.chunks` call in `generate_preprocessed_trace`. + let num_rows = input + .mem_const_count + .checked_sub(1) + .map(|x| x / NUM_MEM_ENTRIES_PER_ROW + 1) + .unwrap_or_default(); + let rows = + std::iter::repeat([F::zero(); NUM_MEM_INIT_COLS]).take(num_rows).collect::>(); + + // Convert the trace to a row major matrix. + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_MEM_INIT_COLS); + + // Pad the trace to a power of two. + pad_to_power_of_two::(&mut trace.values); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl Air for MemoryChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let prep = builder.preprocessed(); + let prep_local = prep.row_slice(0); + let prep_local: &MemoryPreprocessedCols = (*prep_local).borrow(); + + for (value, access) in prep_local.values_and_accesses { + builder.send_block(access.addr, value, access.mult); + } + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use machine::{tests::run_recursion_test_machines, RecursionAir}; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use sp1_core_machine::utils::run_test_machine; + use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; + use sp1_stark::{BabyBearPoseidon2Inner, StarkGenericConfig}; + + use super::*; + + use crate::runtime::instruction as instr; + + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + type EF = ::Challenge; + type A = RecursionAir; + + pub fn prove_program(program: RecursionProgram) { + let program = Arc::new(program); + let mut runtime = Runtime::::new( + program.clone(), + BabyBearPoseidon2Inner::new().perm, + ); + runtime.run().unwrap(); + + let config = SC::new(); + let machine = A::machine_wide(config); + let (pk, vk) = machine.setup(&program); + let result = run_test_machine(vec![runtime.record], machine, pk, vk); + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + } + + #[test] + pub fn generate_trace() { + let shard = ExecutionRecord:: { + mem_var_events: vec![ + MemEvent { inner: BabyBear::one().into() }, + MemEvent { inner: BabyBear::one().into() }, + ], + ..Default::default() + }; + let chip = MemoryChip::default(); + let trace: RowMajorMatrix = + chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } + + #[test] + pub fn prove_basic_mem() { + run_recursion_test_machines(RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 1, 2), + ], + ..Default::default() + }); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_mult() { + prove_program(RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 999, 1, 2), + ], + ..Default::default() + }); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_address() { + prove_program(RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 999, 2), + ], + ..Default::default() + }); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_value() { + prove_program(RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 1, 999), + ], + ..Default::default() + }); + } +} diff --git a/crates/recursion/core-v2/src/chips/mem/mod.rs b/crates/recursion/core-v2/src/chips/mem/mod.rs new file mode 100644 index 0000000000..f318db027a --- /dev/null +++ b/crates/recursion/core-v2/src/chips/mem/mod.rs @@ -0,0 +1,22 @@ +pub mod constant; +pub mod variable; + +pub use constant::MemoryChip as MemoryConstChip; +pub use variable::MemoryChip as MemoryVarChip; + +use sp1_derive::AlignedBorrow; + +use crate::Address; + +pub const NUM_MEM_ACCESS_COLS: usize = core::mem::size_of::>(); + +/// Data describing in what manner to access a particular memory block. +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct MemoryAccessCols { + /// The address to access. + pub addr: Address, + /// The multiplicity which to read/write. + /// "Positive" values indicate a write, and "negative" values indicate a read. + pub mult: F, +} diff --git a/crates/recursion/core-v2/src/chips/mem/variable.rs b/crates/recursion/core-v2/src/chips/mem/variable.rs new file mode 100644 index 0000000000..a2eafb10a3 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/mem/variable.rs @@ -0,0 +1,222 @@ +use core::borrow::Borrow; +use instruction::{HintBitsInstr, HintExt2FeltsInstr, HintInstr}; +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::PrimeField32; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_maybe_rayon::prelude::*; +use sp1_core_machine::utils::{next_power_of_two, pad_to_power_of_two}; +use sp1_derive::AlignedBorrow; +use sp1_stark::air::MachineAir; +use std::{borrow::BorrowMut, iter::zip, marker::PhantomData}; + +use crate::{builder::SP1RecursionAirBuilder, *}; + +use super::{MemoryAccessCols, NUM_MEM_ACCESS_COLS}; + +pub const NUM_MEM_ENTRIES_PER_ROW: usize = 16; + +#[derive(Default)] +pub struct MemoryChip { + _data: PhantomData, +} + +pub const NUM_MEM_INIT_COLS: usize = core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct MemoryCols { + values: [Block; NUM_MEM_ENTRIES_PER_ROW], +} + +pub const NUM_MEM_PREPROCESSED_INIT_COLS: usize = + core::mem::size_of::>(); + +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct MemoryPreprocessedCols { + accesses: [MemoryAccessCols; NUM_MEM_ENTRIES_PER_ROW], +} + +impl BaseAir for MemoryChip { + fn width(&self) -> usize { + NUM_MEM_INIT_COLS + } +} + +impl MachineAir for MemoryChip { + type Record = crate::ExecutionRecord; + + type Program = crate::RecursionProgram; + + fn name(&self) -> String { + "MemoryVar".to_string() + } + fn preprocessed_width(&self) -> usize { + NUM_MEM_PREPROCESSED_INIT_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + // Allocating an intermediate `Vec` is faster. + let accesses = program + .instructions + .par_iter() // Using `rayon` here provides a big speedup. + .flat_map_iter(|instruction| match instruction { + Instruction::Hint(HintInstr { output_addrs_mults }) + | Instruction::HintBits(HintBitsInstr { + output_addrs_mults, + input_addr: _, // No receive interaction for the hint operation + }) => output_addrs_mults.iter().collect(), + Instruction::HintExt2Felts(HintExt2FeltsInstr { + output_addrs_mults, + input_addr: _, // No receive interaction for the hint operation + }) => output_addrs_mults.iter().collect(), + _ => vec![], + }) + .collect::>(); + + let nb_rows = accesses.len().div_ceil(NUM_MEM_ENTRIES_PER_ROW); + let padded_nb_rows = next_power_of_two(nb_rows, None); + let mut values = vec![F::zero(); padded_nb_rows * NUM_MEM_PREPROCESSED_INIT_COLS]; + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let populate_len = accesses.len() * NUM_MEM_ACCESS_COLS; + values[..populate_len] + .par_chunks_mut(NUM_MEM_ACCESS_COLS) + .zip_eq(accesses) + .for_each(|(row, &(addr, mult))| *row.borrow_mut() = MemoryAccessCols { addr, mult }); + + Some(RowMajorMatrix::new(values, NUM_MEM_PREPROCESSED_INIT_COLS)) + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn generate_trace(&self, input: &Self::Record, _: &mut Self::Record) -> RowMajorMatrix { + // Generate the trace rows & corresponding records for each chunk of events in parallel. + let rows = input + .mem_var_events + .chunks(NUM_MEM_ENTRIES_PER_ROW) + .map(|row_events| { + let mut row = [F::zero(); NUM_MEM_INIT_COLS]; + let cols: &mut MemoryCols<_> = row.as_mut_slice().borrow_mut(); + for (cell, vals) in zip(&mut cols.values, row_events) { + *cell = vals.inner; + } + row + }) + .collect::>(); + + // Convert the trace to a row major matrix. + let mut trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_MEM_INIT_COLS); + + // Pad the trace to a power of two. + pad_to_power_of_two::(&mut trace.values); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl Air for MemoryChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &MemoryCols = (*local).borrow(); + let prep = builder.preprocessed(); + let prep_local = prep.row_slice(0); + let prep_local: &MemoryPreprocessedCols = (*prep_local).borrow(); + + for (value, access) in zip(local.values, prep_local.accesses) { + builder.send_block(access.addr, value, access.mult); + } + } +} + +#[cfg(test)] +mod tests { + use machine::tests::run_recursion_test_machines; + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use super::*; + + use crate::runtime::instruction as instr; + + #[test] + pub fn generate_trace() { + let shard = ExecutionRecord:: { + mem_var_events: vec![ + MemEvent { inner: BabyBear::one().into() }, + MemEvent { inner: BabyBear::one().into() }, + ], + ..Default::default() + }; + let chip = MemoryChip::default(); + let trace: RowMajorMatrix = + chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } + + #[test] + pub fn prove_basic_mem() { + let program = RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 1, 2), + ], + ..Default::default() + }; + + run_recursion_test_machines(program); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_mult() { + let program = RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 999, 1, 2), + ], + ..Default::default() + }; + + run_recursion_test_machines(program); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_address() { + let program = RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 999, 2), + ], + ..Default::default() + }; + + run_recursion_test_machines(program); + } + + #[test] + #[should_panic] + pub fn basic_mem_bad_value() { + let program = RecursionProgram { + instructions: vec![ + instr::mem(MemAccessKind::Write, 1, 1, 2), + instr::mem(MemAccessKind::Read, 1, 1, 999), + ], + ..Default::default() + }; + + run_recursion_test_machines(program); + } +} diff --git a/crates/recursion/core-v2/src/chips/mod.rs b/crates/recursion/core-v2/src/chips/mod.rs new file mode 100644 index 0000000000..3a717452c2 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/mod.rs @@ -0,0 +1,9 @@ +pub mod alu_base; +pub mod alu_ext; +pub mod dummy; +pub mod exp_reverse_bits; +pub mod fri_fold; +pub mod mem; +pub mod poseidon2_skinny; +pub mod poseidon2_wide; +pub mod public_values; diff --git a/crates/recursion/core-v2/src/chips/poseidon2_skinny/air.rs b/crates/recursion/core-v2/src/chips/poseidon2_skinny/air.rs new file mode 100644 index 0000000000..7602cd0711 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_skinny/air.rs @@ -0,0 +1,164 @@ +//! The air module contains the AIR constraints for the poseidon2 chip. +//! At the moment, we're only including memory constraints to test the new memory argument. + +use std::{array, borrow::Borrow}; + +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; +use p3_field::AbstractField; +use p3_matrix::Matrix; + +use crate::{builder::SP1RecursionAirBuilder, chips::poseidon2_skinny::columns::Poseidon2}; + +use super::{ + columns::{preprocessed::Poseidon2PreprocessedCols, NUM_POSEIDON2_COLS}, + external_linear_layer, internal_linear_layer, Poseidon2SkinnyChip, NUM_INTERNAL_ROUNDS, WIDTH, +}; + +impl BaseAir for Poseidon2SkinnyChip { + fn width(&self) -> usize { + // We only support machines with degree 9. + assert!(DEGREE >= 9); + NUM_POSEIDON2_COLS + } +} + +impl Air for Poseidon2SkinnyChip +where + AB: SP1RecursionAirBuilder + PairBuilder, + AB::Var: 'static, +{ + fn eval(&self, builder: &mut AB) { + // We only support machines with degree 9. + assert!(DEGREE >= 9); + + let main = builder.main(); + let (local_row, next_row) = (main.row_slice(0), main.row_slice(1)); + let local_row: &Poseidon2<_> = (*local_row).borrow(); + let next_row: &Poseidon2<_> = (*next_row).borrow(); + let prepr = builder.preprocessed(); + let prep_local = prepr.row_slice(0); + let prep_local: &Poseidon2PreprocessedCols<_> = (*prep_local).borrow(); + + // Dummy constraints to normalize to DEGREE. + let lhs = (0..DEGREE).map(|_| local_row.state_var[0].into()).product::(); + let rhs = (0..DEGREE).map(|_| local_row.state_var[0].into()).product::(); + builder.assert_eq(lhs, rhs); + + // For now, include only memory constraints. + (0..WIDTH).for_each(|i| { + builder.send_single( + prep_local.memory_preprocessed[i].addr, + local_row.state_var[i], + prep_local.memory_preprocessed[i].mult, + ) + }); + + self.eval_input_round(builder, local_row, prep_local, next_row); + + self.eval_external_round(builder, local_row, prep_local, next_row); + + self.eval_internal_rounds( + builder, + local_row, + next_row, + prep_local.round_counters_preprocessed.round_constants, + prep_local.round_counters_preprocessed.is_internal_round, + ); + } +} + +impl Poseidon2SkinnyChip { + fn eval_input_round( + &self, + builder: &mut AB, + local_row: &Poseidon2, + prep_local: &Poseidon2PreprocessedCols, + next_row: &Poseidon2, + ) { + let mut state: [AB::Expr; WIDTH] = array::from_fn(|i| local_row.state_var[i].into()); + + // Apply the linear layer. + external_linear_layer(&mut state); + + let next_state = next_row.state_var; + for i in 0..WIDTH { + builder + .when_transition() + .when(prep_local.round_counters_preprocessed.is_input_round) + .assert_eq(next_state[i], state[i].clone()); + } + } + + fn eval_external_round( + &self, + builder: &mut AB, + local_row: &Poseidon2, + prep_local: &Poseidon2PreprocessedCols, + next_row: &Poseidon2, + ) { + let local_state = local_row.state_var; + + // Add the round constants. + let add_rc: [AB::Expr; WIDTH] = core::array::from_fn(|i| { + local_state[i].into() + prep_local.round_counters_preprocessed.round_constants[i] + }); + + // Apply the sboxes. + // See `populate_external_round` for why we don't have columns for the sbox output here. + let mut sbox_deg_7: [AB::Expr; WIDTH] = core::array::from_fn(|_| AB::Expr::zero()); + for i in 0..WIDTH { + let sbox_deg_3 = add_rc[i].clone() * add_rc[i].clone() * add_rc[i].clone(); + sbox_deg_7[i] = sbox_deg_3.clone() * sbox_deg_3.clone() * add_rc[i].clone(); + } + + // Apply the linear layer. + let mut state = sbox_deg_7; + external_linear_layer(&mut state); + + let next_state = next_row.state_var; + for i in 0..WIDTH { + builder + .when_transition() + .when(prep_local.round_counters_preprocessed.is_external_round) + .assert_eq(next_state[i], state[i].clone()); + } + } + + fn eval_internal_rounds( + &self, + builder: &mut AB, + local_row: &Poseidon2, + next_row: &Poseidon2, + round_constants: [AB::Var; WIDTH], + is_internal_row: AB::Var, + ) { + let local_state = local_row.state_var; + + let s0 = local_row.internal_rounds_s0; + let mut state: [AB::Expr; WIDTH] = core::array::from_fn(|i| local_state[i].into()); + for r in 0..NUM_INTERNAL_ROUNDS { + // Add the round constant. + let add_rc = + if r == 0 { state[0].clone() } else { s0[r - 1].into() } + round_constants[r]; + + let sbox_deg_3 = add_rc.clone() * add_rc.clone() * add_rc.clone(); + // See `populate_internal_rounds` for why we don't have columns for the sbox output + // here. + let sbox_deg_7 = sbox_deg_3.clone() * sbox_deg_3.clone() * add_rc.clone(); + + // Apply the linear layer. + // See `populate_internal_rounds` for why we don't have columns for the new state here. + state[0] = sbox_deg_7.clone(); + internal_linear_layer(&mut state); + + if r < NUM_INTERNAL_ROUNDS - 1 { + builder.when(is_internal_row).assert_eq(s0[r], state[0].clone()); + } + } + + let next_state = next_row.state_var; + for i in 0..WIDTH { + builder.when(is_internal_row).assert_eq(next_state[i], state[i].clone()) + } + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/mod.rs b/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/mod.rs new file mode 100644 index 0000000000..7338082179 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/mod.rs @@ -0,0 +1,23 @@ +use std::mem::{size_of, transmute}; + +use sp1_core_machine::utils::indices_arr; +use sp1_derive::AlignedBorrow; + +use crate::chips::poseidon2_skinny::{NUM_INTERNAL_ROUNDS, WIDTH}; + +pub mod preprocessed; + +pub const NUM_POSEIDON2_COLS: usize = size_of::>(); +const fn make_col_map_degree9() -> Poseidon2 { + let indices_arr = indices_arr::(); + unsafe { transmute::<[usize; NUM_POSEIDON2_COLS], Poseidon2>(indices_arr) } +} +pub const POSEIDON2_DEGREE9_COL_MAP: Poseidon2 = make_col_map_degree9(); + +/// Struct for the poseidon2 skinny non preprocessed column. +#[derive(AlignedBorrow, Clone, Copy)] +#[repr(C)] +pub struct Poseidon2 { + pub state_var: [T; WIDTH], + pub internal_rounds_s0: [T; NUM_INTERNAL_ROUNDS - 1], +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/preprocessed.rs b/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/preprocessed.rs new file mode 100644 index 0000000000..02f5e041a8 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_skinny/columns/preprocessed.rs @@ -0,0 +1,19 @@ +use sp1_derive::AlignedBorrow; + +use crate::chips::{mem::MemoryAccessCols, poseidon2_skinny::WIDTH}; + +#[derive(AlignedBorrow, Clone, Copy, Debug)] +#[repr(C)] +pub struct RoundCountersPreprocessedCols { + pub is_input_round: T, + pub is_external_round: T, + pub is_internal_round: T, + pub round_constants: [T; WIDTH], +} + +#[derive(AlignedBorrow, Clone, Copy, Debug)] +#[repr(C)] +pub struct Poseidon2PreprocessedCols { + pub memory_preprocessed: [MemoryAccessCols; WIDTH], + pub round_counters_preprocessed: RoundCountersPreprocessedCols, +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_skinny/mod.rs b/crates/recursion/core-v2/src/chips/poseidon2_skinny/mod.rs new file mode 100644 index 0000000000..332075143f --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_skinny/mod.rs @@ -0,0 +1,151 @@ +use p3_baby_bear::{MONTY_INVERSE, POSEIDON2_INTERNAL_MATRIX_DIAG_16_BABYBEAR_MONTY}; +use p3_field::{AbstractField, PrimeField32}; + +pub mod air; +pub mod columns; +pub mod trace; + +use p3_poseidon2::matmul_internal; + +/// The width of the permutation. +pub const WIDTH: usize = 16; +pub const RATE: usize = WIDTH / 2; + +pub const NUM_EXTERNAL_ROUNDS: usize = 8; +pub const NUM_INTERNAL_ROUNDS: usize = 13; +pub const NUM_ROUNDS: usize = NUM_EXTERNAL_ROUNDS + NUM_INTERNAL_ROUNDS; + +/// A chip that implements the Poseidon2 permutation in the skinny variant (one external round per +/// row and one row for all internal rounds). +pub struct Poseidon2SkinnyChip { + pub fixed_log2_rows: Option, + pub pad: bool, +} + +impl Default for Poseidon2SkinnyChip { + fn default() -> Self { + // We only support machines with degree 9. + assert!(DEGREE >= 9); + Self { fixed_log2_rows: None, pad: true } + } +} +pub fn apply_m_4(x: &mut [AF]) +where + AF: AbstractField, +{ + let t01 = x[0].clone() + x[1].clone(); + let t23 = x[2].clone() + x[3].clone(); + let t0123 = t01.clone() + t23.clone(); + let t01123 = t0123.clone() + x[1].clone(); + let t01233 = t0123.clone() + x[3].clone(); + // The order here is important. Need to overwrite x[0] and x[2] after x[1] and x[3]. + x[3] = t01233.clone() + x[0].double(); // 3*x[0] + x[1] + x[2] + 2*x[3] + x[1] = t01123.clone() + x[2].double(); // x[0] + 2*x[1] + 3*x[2] + x[3] + x[0] = t01123 + t01; // 2*x[0] + 3*x[1] + x[2] + x[3] + x[2] = t01233 + t23; // x[0] + x[1] + 2*x[2] + 3*x[3] +} + +pub(crate) fn external_linear_layer(state: &mut [AF; WIDTH]) { + for j in (0..WIDTH).step_by(4) { + apply_m_4(&mut state[j..j + 4]); + } + let sums: [AF; 4] = + core::array::from_fn(|k| (0..WIDTH).step_by(4).map(|j| state[j + k].clone()).sum::()); + + for j in 0..WIDTH { + state[j] += sums[j % 4].clone(); + } +} + +pub(crate) fn internal_linear_layer(state: &mut [F; WIDTH]) { + let matmul_constants: [::F; WIDTH] = + POSEIDON2_INTERNAL_MATRIX_DIAG_16_BABYBEAR_MONTY + .iter() + .map(|x| ::F::from_wrapped_u32(x.as_canonical_u32())) + .collect::>() + .try_into() + .unwrap(); + matmul_internal(state, matmul_constants); + let monty_inverse = F::from_wrapped_u32(MONTY_INVERSE.as_canonical_u32()); + state.iter_mut().for_each(|i| *i *= monty_inverse.clone()); +} + +#[cfg(test)] +pub(crate) mod tests { + + use std::{iter::once, sync::Arc}; + + use crate::{ + machine::RecursionAir, runtime::instruction as instr, MemAccessKind, RecursionProgram, + Runtime, + }; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_field::{AbstractField, PrimeField32}; + use p3_symmetric::Permutation; + + use sp1_core_machine::utils::{run_test_machine, setup_logger}; + use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, inner_perm, StarkGenericConfig}; + use zkhash::ark_ff::UniformRand; + + use super::WIDTH; + + #[test] + fn test_poseidon2() { + setup_logger(); + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + type EF = ::Challenge; + type B = RecursionAir; + + let input = [1; WIDTH]; + let output = inner_perm() + .permute(input.map(BabyBear::from_canonical_u32)) + .map(|x| BabyBear::as_canonical_u32(&x)); + + let rng = &mut rand::thread_rng(); + let input_1: [BabyBear; WIDTH] = std::array::from_fn(|_| BabyBear::rand(rng)); + let output_1 = inner_perm().permute(input_1).map(|x| BabyBear::as_canonical_u32(&x)); + let input_1 = input_1.map(|x| BabyBear::as_canonical_u32(&x)); + + let instructions = + (0..WIDTH) + .map(|i| instr::mem(MemAccessKind::Write, 1, i as u32, input[i])) + .chain(once(instr::poseidon2( + [1; WIDTH], + std::array::from_fn(|i| (i + WIDTH) as u32), + std::array::from_fn(|i| i as u32), + ))) + .chain( + (0..WIDTH) + .map(|i| instr::mem(MemAccessKind::Read, 1, (i + WIDTH) as u32, output[i])), + ) + .chain((0..WIDTH).map(|i| { + instr::mem(MemAccessKind::Write, 1, (2 * WIDTH + i) as u32, input_1[i]) + })) + .chain(once(instr::poseidon2( + [1; WIDTH], + std::array::from_fn(|i| (i + 3 * WIDTH) as u32), + std::array::from_fn(|i| (i + 2 * WIDTH) as u32), + ))) + .chain((0..WIDTH).map(|i| { + instr::mem(MemAccessKind::Read, 1, (i + 3 * WIDTH) as u32, output_1[i]) + })) + .collect::>(); + + let program = Arc::new(RecursionProgram { instructions, ..Default::default() }); + let mut runtime = Runtime::::new( + program.clone(), + BabyBearPoseidon2::new().perm, + ); + runtime.run().unwrap(); + + let config = SC::new(); + let machine_deg_9 = B::machine(config); + let (pk_9, vk_9) = machine_deg_9.setup(&program); + let result_deg_9 = run_test_machine(vec![runtime.record], machine_deg_9, pk_9, vk_9); + if let Err(e) = result_deg_9 { + panic!("Verification failed: {:?}", e); + } + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_skinny/trace.rs b/crates/recursion/core-v2/src/chips/poseidon2_skinny/trace.rs new file mode 100644 index 0000000000..cddde880a1 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_skinny/trace.rs @@ -0,0 +1,311 @@ +use std::{ + array, + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; + +use itertools::Itertools; +use p3_field::PrimeField32; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_rows_fixed; +use sp1_primitives::RC_16_30_U32; +use sp1_stark::air::MachineAir; +use tracing::instrument; + +use crate::{ + chips::{ + mem::MemoryAccessCols, + poseidon2_skinny::{ + columns::{Poseidon2 as Poseidon2Cols, NUM_POSEIDON2_COLS}, + external_linear_layer, Poseidon2SkinnyChip, NUM_EXTERNAL_ROUNDS, NUM_INTERNAL_ROUNDS, + }, + }, + instruction::Instruction::Poseidon2, + ExecutionRecord, RecursionProgram, +}; + +use super::{columns::preprocessed::Poseidon2PreprocessedCols, internal_linear_layer, WIDTH}; + +const PREPROCESSED_POSEIDON2_WIDTH: usize = size_of::>(); + +const INTERNAL_ROUND_IDX: usize = NUM_EXTERNAL_ROUNDS / 2 + 1; +const INPUT_ROUND_IDX: usize = 0; +const OUTPUT_ROUND_IDX: usize = NUM_EXTERNAL_ROUNDS + 2; + +impl MachineAir for Poseidon2SkinnyChip { + type Record = ExecutionRecord; + + type Program = RecursionProgram; + + fn name(&self) -> String { + format!("Poseidon2SkinnyDeg{}", DEGREE) + } + + #[instrument(name = "generate poseidon2 skinny trace", level = "debug", skip_all, fields(rows = input.poseidon2_events.len()))] + fn generate_trace( + &self, + input: &ExecutionRecord, + _output: &mut ExecutionRecord, + ) -> RowMajorMatrix { + let mut rows = Vec::new(); + + for event in &input.poseidon2_events { + // We have one row for input, one row for output, NUM_EXTERNAL_ROUNDS rows for the + // external rounds, and one row for all internal rounds. + let mut row_add = [[F::zero(); NUM_POSEIDON2_COLS]; NUM_EXTERNAL_ROUNDS + 3]; + + // The first row should have event.input and [event.input[0].clone(); + // NUM_INTERNAL_ROUNDS-1] in its state columns. The sbox_state will be + // modified in the computation of the first row. + { + let (first_row, second_row) = &mut row_add[0..2].split_at_mut(1); + let input_cols: &mut Poseidon2Cols = first_row[0].as_mut_slice().borrow_mut(); + input_cols.state_var = event.input; + + let next_cols: &mut Poseidon2Cols = second_row[0].as_mut_slice().borrow_mut(); + next_cols.state_var = event.input; + external_linear_layer(&mut next_cols.state_var); + } + + // For each external round, and once for all the internal rounds at the same time, apply + // the corresponding operation. This will change the state and internal_rounds_s0 + // variable in row r+1. + for i in 1..OUTPUT_ROUND_IDX { + let next_state_var = { + let cols: &mut Poseidon2Cols = row_add[i].as_mut_slice().borrow_mut(); + let state = cols.state_var; + + if i != INTERNAL_ROUND_IDX { + self.populate_external_round(&state, i - 1) + } else { + // Populate the internal rounds. + self.populate_internal_rounds(&state, &mut cols.internal_rounds_s0) + } + }; + let next_row_cols: &mut Poseidon2Cols = + row_add[i + 1].as_mut_slice().borrow_mut(); + next_row_cols.state_var = next_state_var; + } + + // Check that the permutation is computed correctly. + { + let last_row_cols: &Poseidon2Cols = + row_add[OUTPUT_ROUND_IDX].as_slice().borrow(); + debug_assert_eq!(last_row_cols.state_var, event.output); + } + rows.extend(row_add.into_iter()); + } + + if self.pad { + // Pad the trace to a power of two. + // This will need to be adjusted when the AIR constraints are implemented. + pad_rows_fixed(&mut rows, || [F::zero(); NUM_POSEIDON2_COLS], self.fixed_log2_rows); + } + + // Convert the trace to a row major matrix. + let trace = + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_POSEIDON2_COLS); + + #[cfg(debug_assertions)] + println!( + "poseidon2 skinny main trace dims is width: {:?}, height: {:?}", + trace.width(), + trace.height() + ); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } + + fn preprocessed_width(&self) -> usize { + PREPROCESSED_POSEIDON2_WIDTH + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + let instructions = + program.instructions.iter().filter_map(|instruction| match instruction { + Poseidon2(instr) => Some(instr), + _ => None, + }); + + let num_instructions = instructions.clone().count(); + + let mut rows = vec![ + [F::zero(); PREPROCESSED_POSEIDON2_WIDTH]; + num_instructions * (NUM_EXTERNAL_ROUNDS + 3) + ]; + + // Iterate over the instructions and take NUM_EXTERNAL_ROUNDS + 3 rows for each instruction. + // We have one extra round for the internal rounds, one extra round for the input, + // and one extra round for the output. + instructions.zip_eq(&rows.iter_mut().chunks(NUM_EXTERNAL_ROUNDS + 3)).for_each( + |(instruction, row_add)| { + row_add.into_iter().enumerate().for_each(|(i, row)| { + let cols: &mut Poseidon2PreprocessedCols<_> = + (*row).as_mut_slice().borrow_mut(); + + // Set the round-counter columns. + cols.round_counters_preprocessed.is_input_round = + F::from_bool(i == INPUT_ROUND_IDX); + let is_external_round = + i != INPUT_ROUND_IDX && i != INTERNAL_ROUND_IDX && i != OUTPUT_ROUND_IDX; + cols.round_counters_preprocessed.is_external_round = + F::from_bool(is_external_round); + cols.round_counters_preprocessed.is_internal_round = + F::from_bool(i == INTERNAL_ROUND_IDX); + + (0..WIDTH).for_each(|j| { + cols.round_counters_preprocessed.round_constants[j] = if is_external_round { + let r = i - 1; + let round = if i < INTERNAL_ROUND_IDX { + r + } else { + r + NUM_INTERNAL_ROUNDS - 1 + }; + + F::from_wrapped_u32(RC_16_30_U32[round][j]) + } else if i == INTERNAL_ROUND_IDX { + F::from_wrapped_u32(RC_16_30_U32[NUM_EXTERNAL_ROUNDS / 2 + j][0]) + } else { + F::zero() + }; + }); + + // Set the memory columns. We read once, at the first iteration, + // and write once, at the last iteration. + if i == INPUT_ROUND_IDX { + cols.memory_preprocessed = instruction + .addrs + .input + .map(|addr| MemoryAccessCols { addr, mult: F::neg_one() }); + } else if i == OUTPUT_ROUND_IDX { + cols.memory_preprocessed = array::from_fn(|i| MemoryAccessCols { + addr: instruction.addrs.output[i], + mult: instruction.mults[i], + }); + } + }); + }, + ); + if self.pad { + // Pad the trace to a power of two. + // This may need to be adjusted when the AIR constraints are implemented. + pad_rows_fixed( + &mut rows, + || [F::zero(); PREPROCESSED_POSEIDON2_WIDTH], + self.fixed_log2_rows, + ); + } + let trace_rows = rows.into_iter().flatten().collect::>(); + Some(RowMajorMatrix::new(trace_rows, PREPROCESSED_POSEIDON2_WIDTH)) + } +} + +impl Poseidon2SkinnyChip { + fn populate_external_round( + &self, + round_state: &[F; WIDTH], + r: usize, + ) -> [F; WIDTH] { + let mut state = { + // Add round constants. + + // Optimization: Since adding a constant is a degree 1 operation, we can avoid adding + // columns for it, and instead include it in the constraint for the x^3 part of the + // sbox. + let round = if r < NUM_EXTERNAL_ROUNDS / 2 { r } else { r + NUM_INTERNAL_ROUNDS - 1 }; + let mut add_rc = *round_state; + (0..WIDTH).for_each(|i| add_rc[i] += F::from_wrapped_u32(RC_16_30_U32[round][i])); + + // Apply the sboxes. + // Optimization: since the linear layer that comes after the sbox is degree 1, we can + // avoid adding columns for the result of the sbox, and instead include the x^3 -> x^7 + // part of the sbox in the constraint for the linear layer + let mut sbox_deg_7: [F; 16] = [F::zero(); WIDTH]; + for i in 0..WIDTH { + let sbox_deg_3 = add_rc[i] * add_rc[i] * add_rc[i]; + sbox_deg_7[i] = sbox_deg_3 * sbox_deg_3 * add_rc[i]; + } + + sbox_deg_7 + }; + // Apply the linear layer. + external_linear_layer(&mut state); + state + } + + fn populate_internal_rounds( + &self, + state: &[F; WIDTH], + internal_rounds_s0: &mut [F; NUM_INTERNAL_ROUNDS - 1], + ) -> [F; WIDTH] { + let mut new_state = *state; + (0..NUM_INTERNAL_ROUNDS).for_each(|r| { + // Add the round constant to the 0th state element. + // Optimization: Since adding a constant is a degree 1 operation, we can avoid adding + // columns for it, just like for external rounds. + let round = r + NUM_EXTERNAL_ROUNDS / 2; + let add_rc = new_state[0] + F::from_wrapped_u32(RC_16_30_U32[round][0]); + + // Apply the sboxes. + // Optimization: since the linear layer that comes after the sbox is degree 1, we can + // avoid adding columns for the result of the sbox, just like for external rounds. + let sbox_deg_3 = add_rc * add_rc * add_rc; + let sbox_deg_7 = sbox_deg_3 * sbox_deg_3 * add_rc; + + // Apply the linear layer. + new_state[0] = sbox_deg_7; + internal_linear_layer(&mut new_state); + + // Optimization: since we're only applying the sbox to the 0th state element, we only + // need to have columns for the 0th state element at every step. This is because the + // linear layer is degree 1, so all state elements at the end can be expressed as a + // degree-3 polynomial of the state at the beginning of the internal rounds and the 0th + // state element at rounds prior to the current round + if r < NUM_INTERNAL_ROUNDS - 1 { + internal_rounds_s0[r] = new_state[0]; + } + }); + + new_state + } +} + +#[cfg(test)] +mod tests { + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + use p3_symmetric::Permutation; + use sp1_stark::{air::MachineAir, inner_perm}; + use zkhash::ark_ff::UniformRand; + + use crate::{ + chips::poseidon2_skinny::{Poseidon2SkinnyChip, WIDTH}, + ExecutionRecord, Poseidon2Event, + }; + + #[test] + fn generate_trace() { + type F = BabyBear; + let input_0 = [F::one(); WIDTH]; + let permuter = inner_perm(); + let output_0 = permuter.permute(input_0); + let mut rng = rand::thread_rng(); + + let input_1 = [F::rand(&mut rng); WIDTH]; + let output_1 = permuter.permute(input_1); + let shard = ExecutionRecord { + poseidon2_events: vec![ + Poseidon2Event { input: input_0, output: output_0 }, + Poseidon2Event { input: input_1, output: output_1 }, + ], + ..Default::default() + }; + let chip_9 = Poseidon2SkinnyChip::<9>::default(); + let _: RowMajorMatrix = chip_9.generate_trace(&shard, &mut ExecutionRecord::default()); + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/air.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/air.rs new file mode 100644 index 0000000000..393910bdac --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/air.rs @@ -0,0 +1,179 @@ +//! The air module contains the AIR constraints for the poseidon2 chip. +//! At the moment, we're only including memory constraints to test the new memory argument. + +use std::{array, borrow::Borrow}; + +use p3_air::{Air, BaseAir, PairBuilder}; +use p3_field::AbstractField; +use p3_matrix::Matrix; +use sp1_primitives::RC_16_30_U32; +use sp1_recursion_core::poseidon2_wide::NUM_EXTERNAL_ROUNDS; + +use crate::builder::SP1RecursionAirBuilder; + +use super::{ + columns::{ + permutation::Poseidon2, preprocessed::Poseidon2PreprocessedCols, + NUM_POSEIDON2_DEGREE3_COLS, NUM_POSEIDON2_DEGREE9_COLS, + }, + external_linear_layer, internal_linear_layer, Poseidon2WideChip, NUM_INTERNAL_ROUNDS, WIDTH, +}; + +impl BaseAir for Poseidon2WideChip { + fn width(&self) -> usize { + if DEGREE == 3 { + NUM_POSEIDON2_DEGREE3_COLS + } else if DEGREE == 9 || DEGREE == 17 { + NUM_POSEIDON2_DEGREE9_COLS + } else { + panic!("Unsupported degree: {}", DEGREE); + } + } +} + +impl Air for Poseidon2WideChip +where + AB: SP1RecursionAirBuilder + PairBuilder, + AB::Var: 'static, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let prepr = builder.preprocessed(); + let local_row = Self::convert::(main.row_slice(0)); + let prep_local = prepr.row_slice(0); + let prep_local: &Poseidon2PreprocessedCols<_> = (*prep_local).borrow(); + + // Dummy constraints to normalize to DEGREE. + let lhs = (0..DEGREE) + .map(|_| local_row.external_rounds_state()[0][0].into()) + .product::(); + let rhs = (0..DEGREE) + .map(|_| local_row.external_rounds_state()[0][0].into()) + .product::(); + builder.assert_eq(lhs, rhs); + + // For now, include only memory constraints. + (0..WIDTH).for_each(|i| { + builder.send_single( + prep_local.input[i], + local_row.external_rounds_state()[0][i], + prep_local.is_real_neg, + ) + }); + + (0..WIDTH).for_each(|i| { + builder.send_single( + prep_local.output[i].addr, + local_row.perm_output()[i], + prep_local.output[i].mult, + ) + }); + + // Apply the external rounds. + for r in 0..NUM_EXTERNAL_ROUNDS { + self.eval_external_round(builder, local_row.as_ref(), r); + } + + // Apply the internal rounds. + self.eval_internal_rounds(builder, local_row.as_ref()); + } +} + +impl Poseidon2WideChip { + /// Eval the constraints for the external rounds. + fn eval_external_round( + &self, + builder: &mut AB, + local_row: &dyn Poseidon2, + r: usize, + ) where + AB: SP1RecursionAirBuilder + PairBuilder, + { + let mut local_state: [AB::Expr; WIDTH] = + array::from_fn(|i| local_row.external_rounds_state()[r][i].into()); + + // For the first round, apply the linear layer. + if r == 0 { + external_linear_layer(&mut local_state); + } + + // Add the round constants. + let round = if r < NUM_EXTERNAL_ROUNDS / 2 { r } else { r + NUM_INTERNAL_ROUNDS }; + let add_rc: [AB::Expr; WIDTH] = array::from_fn(|i| { + local_state[i].clone() + AB::F::from_wrapped_u32(RC_16_30_U32[round][i]) + }); + + // Apply the sboxes. + // See `populate_external_round` for why we don't have columns for the sbox output here. + let mut sbox_deg_7: [AB::Expr; WIDTH] = core::array::from_fn(|_| AB::Expr::zero()); + let mut sbox_deg_3: [AB::Expr; WIDTH] = core::array::from_fn(|_| AB::Expr::zero()); + for i in 0..WIDTH { + let calculated_sbox_deg_3 = add_rc[i].clone() * add_rc[i].clone() * add_rc[i].clone(); + + if let Some(external_sbox) = local_row.external_rounds_sbox() { + // builder.assert_eq(external_sbox[r][i].into(), calculated_sbox_deg_3); + sbox_deg_3[i] = external_sbox[r][i].into(); + } else { + sbox_deg_3[i] = calculated_sbox_deg_3; + } + + sbox_deg_7[i] = sbox_deg_3[i].clone() * sbox_deg_3[i].clone() * add_rc[i].clone(); + } + + // Apply the linear layer. + let mut state = sbox_deg_7; + external_linear_layer(&mut state); + + let next_state = if r == (NUM_EXTERNAL_ROUNDS / 2) - 1 { + local_row.internal_rounds_state() + } else if r == NUM_EXTERNAL_ROUNDS - 1 { + local_row.perm_output() + } else { + &local_row.external_rounds_state()[r + 1] + }; + + for i in 0..WIDTH { + builder.assert_eq(next_state[i], state[i].clone()); + } + } + + /// Eval the constraints for the internal rounds. + fn eval_internal_rounds(&self, builder: &mut AB, local_row: &dyn Poseidon2) + where + AB: SP1RecursionAirBuilder + PairBuilder, + { + let state = &local_row.internal_rounds_state(); + let s0 = local_row.internal_rounds_s0(); + let mut state: [AB::Expr; WIDTH] = core::array::from_fn(|i| state[i].into()); + for r in 0..NUM_INTERNAL_ROUNDS { + // Add the round constant. + let round = r + NUM_EXTERNAL_ROUNDS / 2; + let add_rc = if r == 0 { state[0].clone() } else { s0[r - 1].into() } + + AB::Expr::from_wrapped_u32(RC_16_30_U32[round][0]); + + let mut sbox_deg_3 = add_rc.clone() * add_rc.clone() * add_rc.clone(); + if let Some(internal_sbox) = local_row.internal_rounds_sbox() { + builder.assert_eq(internal_sbox[r], sbox_deg_3); + sbox_deg_3 = internal_sbox[r].into(); + } + + // See `populate_internal_rounds` for why we don't have columns for the sbox output + // here. + let sbox_deg_7 = sbox_deg_3.clone() * sbox_deg_3.clone() * add_rc.clone(); + + // Apply the linear layer. + // See `populate_internal_rounds` for why we don't have columns for the new state here. + state[0] = sbox_deg_7.clone(); + internal_linear_layer(&mut state); + + if r < NUM_INTERNAL_ROUNDS - 1 { + builder.assert_eq(s0[r], state[0].clone()); + } + } + + let external_state = local_row.external_rounds_state()[NUM_EXTERNAL_ROUNDS / 2]; + for i in 0..WIDTH { + builder.assert_eq(external_state[i], state[i].clone()) + } + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/mod.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/mod.rs new file mode 100644 index 0000000000..4b90a75c8f --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/mod.rs @@ -0,0 +1,31 @@ +use std::mem::{size_of, transmute}; + +use permutation::{PermutationNoSbox, PermutationSBox}; +use sp1_core_machine::utils::indices_arr; + +pub mod permutation; +pub mod preprocessed; + +pub const POSEIDON2_DEGREE3_COL_MAP: Poseidon2Degree3 = make_col_map_degree3(); +pub const NUM_POSEIDON2_DEGREE3_COLS: usize = size_of::>(); + +const fn make_col_map_degree3() -> Poseidon2Degree3 { + let indices_arr = indices_arr::(); + unsafe { + transmute::<[usize; NUM_POSEIDON2_DEGREE3_COLS], Poseidon2Degree3>(indices_arr) + } +} + +/// Struct for the poseidon2 chip that contains sbox columns. +pub type Poseidon2Degree3 = PermutationSBox; + +pub const NUM_POSEIDON2_DEGREE9_COLS: usize = size_of::>(); +const fn make_col_map_degree9() -> Poseidon2Degree9 { + let indices_arr = indices_arr::(); + unsafe { + transmute::<[usize; NUM_POSEIDON2_DEGREE9_COLS], Poseidon2Degree9>(indices_arr) + } +} +pub const POSEIDON2_DEGREE9_COL_MAP: Poseidon2Degree9 = make_col_map_degree9(); + +pub type Poseidon2Degree9 = PermutationNoSbox; diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/permutation.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/permutation.rs new file mode 100644 index 0000000000..54f54d4076 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/permutation.rs @@ -0,0 +1,223 @@ +use std::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; + +use sp1_derive::AlignedBorrow; +use sp1_recursion_core::poseidon2_wide::NUM_EXTERNAL_ROUNDS; + +use crate::chips::poseidon2_wide::{NUM_INTERNAL_ROUNDS, WIDTH}; + +use super::{POSEIDON2_DEGREE3_COL_MAP, POSEIDON2_DEGREE9_COL_MAP}; + +pub const fn max(a: usize, b: usize) -> usize { + if a > b { + a + } else { + b + } +} + +#[derive(AlignedBorrow, Clone, Copy)] +#[repr(C)] +pub struct PermutationState { + pub external_rounds_state: [[T; WIDTH]; NUM_EXTERNAL_ROUNDS], + pub internal_rounds_state: [T; WIDTH], + pub internal_rounds_s0: [T; NUM_INTERNAL_ROUNDS - 1], + pub output_state: [T; WIDTH], +} + +#[derive(AlignedBorrow, Clone, Copy)] +#[repr(C)] +pub struct PermutationSBoxState { + pub external_rounds_sbox_state: [[T; WIDTH]; NUM_EXTERNAL_ROUNDS], + pub internal_rounds_sbox_state: [T; NUM_INTERNAL_ROUNDS], +} + +/// Trait that describes getter functions for the permutation columns. +pub trait Poseidon2 { + fn external_rounds_state(&self) -> &[[T; WIDTH]]; + + fn internal_rounds_state(&self) -> &[T; WIDTH]; + + fn internal_rounds_s0(&self) -> &[T; NUM_INTERNAL_ROUNDS - 1]; + + fn external_rounds_sbox(&self) -> Option<&[[T; WIDTH]; NUM_EXTERNAL_ROUNDS]>; + + fn internal_rounds_sbox(&self) -> Option<&[T; NUM_INTERNAL_ROUNDS]>; + + fn perm_output(&self) -> &[T; WIDTH]; +} + +/// Trait that describes setter functions for the permutation columns. +pub trait Poseidon2Mut { + #[allow(clippy::type_complexity)] + fn get_cols_mut( + &mut self, + ) -> ( + &mut [[T; WIDTH]], + &mut [T; WIDTH], + &mut [T; NUM_INTERNAL_ROUNDS - 1], + Option<&mut [[T; WIDTH]; NUM_EXTERNAL_ROUNDS]>, + Option<&mut [T; NUM_INTERNAL_ROUNDS]>, + &mut [T; WIDTH], + ); +} + +/// Permutation columns struct with S-boxes. +#[derive(AlignedBorrow, Clone, Copy)] +#[repr(C)] +pub struct PermutationSBox { + pub state: PermutationState, + pub sbox_state: PermutationSBoxState, +} + +impl Poseidon2 for PermutationSBox { + fn external_rounds_state(&self) -> &[[T; WIDTH]] { + &self.state.external_rounds_state + } + + fn internal_rounds_state(&self) -> &[T; WIDTH] { + &self.state.internal_rounds_state + } + + fn internal_rounds_s0(&self) -> &[T; NUM_INTERNAL_ROUNDS - 1] { + &self.state.internal_rounds_s0 + } + + fn external_rounds_sbox(&self) -> Option<&[[T; WIDTH]; NUM_EXTERNAL_ROUNDS]> { + Some(&self.sbox_state.external_rounds_sbox_state) + } + + fn internal_rounds_sbox(&self) -> Option<&[T; NUM_INTERNAL_ROUNDS]> { + Some(&self.sbox_state.internal_rounds_sbox_state) + } + + fn perm_output(&self) -> &[T; WIDTH] { + &self.state.output_state + } +} + +impl Poseidon2Mut for PermutationSBox { + fn get_cols_mut( + &mut self, + ) -> ( + &mut [[T; WIDTH]], + &mut [T; WIDTH], + &mut [T; NUM_INTERNAL_ROUNDS - 1], + Option<&mut [[T; WIDTH]; NUM_EXTERNAL_ROUNDS]>, + Option<&mut [T; NUM_INTERNAL_ROUNDS]>, + &mut [T; WIDTH], + ) { + ( + &mut self.state.external_rounds_state, + &mut self.state.internal_rounds_state, + &mut self.state.internal_rounds_s0, + Some(&mut self.sbox_state.external_rounds_sbox_state), + Some(&mut self.sbox_state.internal_rounds_sbox_state), + &mut self.state.output_state, + ) + } +} + +/// Permutation columns struct without S-boxes. +#[derive(AlignedBorrow, Clone, Copy)] +#[repr(C)] +pub struct PermutationNoSbox { + pub state: PermutationState, +} + +impl Poseidon2 for PermutationNoSbox { + fn external_rounds_state(&self) -> &[[T; WIDTH]] { + &self.state.external_rounds_state + } + + fn internal_rounds_state(&self) -> &[T; WIDTH] { + &self.state.internal_rounds_state + } + + fn internal_rounds_s0(&self) -> &[T; NUM_INTERNAL_ROUNDS - 1] { + &self.state.internal_rounds_s0 + } + + fn external_rounds_sbox(&self) -> Option<&[[T; WIDTH]; NUM_EXTERNAL_ROUNDS]> { + None + } + + fn internal_rounds_sbox(&self) -> Option<&[T; NUM_INTERNAL_ROUNDS]> { + None + } + + fn perm_output(&self) -> &[T; WIDTH] { + &self.state.output_state + } +} + +impl Poseidon2Mut for PermutationNoSbox { + fn get_cols_mut( + &mut self, + ) -> ( + &mut [[T; WIDTH]], + &mut [T; WIDTH], + &mut [T; NUM_INTERNAL_ROUNDS - 1], + Option<&mut [[T; WIDTH]; NUM_EXTERNAL_ROUNDS]>, + Option<&mut [T; NUM_INTERNAL_ROUNDS]>, + &mut [T; WIDTH], + ) { + ( + &mut self.state.external_rounds_state, + &mut self.state.internal_rounds_state, + &mut self.state.internal_rounds_s0, + None, + None, + &mut self.state.output_state, + ) + } +} + +/// Permutation columns struct without S-boxes and half of the external rounds. +/// In the past, all external rounds were stored in one row, so this was a distinct struct, but +/// now the structs don't track the number of external rounds. +pub type PermutationNoSboxHalfExternal = PermutationNoSbox; + +pub fn permutation_mut<'a, 'b: 'a, T, const DEGREE: usize>( + row: &'b mut [T], +) -> Box<&mut (dyn Poseidon2Mut + 'a)> +where + T: Copy, +{ + if DEGREE == 3 { + let start = POSEIDON2_DEGREE3_COL_MAP.state.external_rounds_state[0][0]; + let end = start + size_of::>(); + let convert: &mut PermutationSBox = row[start..end].borrow_mut(); + Box::new(convert) + } else if DEGREE == 9 || DEGREE == 17 { + let start = POSEIDON2_DEGREE9_COL_MAP.state.external_rounds_state[0][0]; + let end = start + size_of::>(); + + let convert: &mut PermutationNoSbox = row[start..end].borrow_mut(); + Box::new(convert) + } else { + panic!("Unsupported degree"); + } +} + +pub fn permutation<'a, 'b: 'a, T, const DEGREE: usize>(row: &'b [T]) -> Box + 'a> +where + T: Copy, +{ + if DEGREE == 3 { + let start = POSEIDON2_DEGREE3_COL_MAP.state.external_rounds_state[0][0]; + let end = start + size_of::>(); + let convert: PermutationSBox = *row[start..end].borrow(); + Box::new(convert) + } else if DEGREE == 9 || DEGREE == 17 { + let start = POSEIDON2_DEGREE9_COL_MAP.state.external_rounds_state[0][0]; + let end = start + size_of::>(); + + let convert: PermutationNoSbox = *row[start..end].borrow(); + Box::new(convert) + } else { + panic!("Unsupported degree"); + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/preprocessed.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/preprocessed.rs new file mode 100644 index 0000000000..41ec59cd76 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/columns/preprocessed.rs @@ -0,0 +1,14 @@ +use sp1_derive::AlignedBorrow; + +use crate::{ + chips::{mem::MemoryAccessCols, poseidon2_wide::WIDTH}, + Address, +}; + +#[derive(AlignedBorrow, Clone, Copy, Debug)] +#[repr(C)] +pub struct Poseidon2PreprocessedCols { + pub input: [Address; WIDTH], + pub output: [MemoryAccessCols; WIDTH], + pub is_real_neg: T, +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/mod.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/mod.rs new file mode 100644 index 0000000000..bf976e1e4d --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/mod.rs @@ -0,0 +1,191 @@ +#![allow(clippy::needless_range_loop)] + +use std::{borrow::Borrow, ops::Deref}; + +use p3_baby_bear::{MONTY_INVERSE, POSEIDON2_INTERNAL_MATRIX_DIAG_16_BABYBEAR_MONTY}; +use p3_field::{AbstractField, PrimeField32}; + +pub mod air; +pub mod columns; +pub mod trace; + +use p3_poseidon2::matmul_internal; + +use self::columns::{permutation::Poseidon2, Poseidon2Degree3, Poseidon2Degree9}; + +/// The width of the permutation. +pub const WIDTH: usize = 16; +pub const RATE: usize = WIDTH / 2; + +pub const NUM_EXTERNAL_ROUNDS: usize = 8; +pub const NUM_INTERNAL_ROUNDS: usize = 13; +pub const NUM_ROUNDS: usize = NUM_EXTERNAL_ROUNDS + NUM_INTERNAL_ROUNDS; + +/// A chip that implements addition for the opcode Poseidon2Wide. +pub struct Poseidon2WideChip { + pub fixed_log2_rows: Option, + pub pad: bool, +} + +impl Default for Poseidon2WideChip { + fn default() -> Self { + Self { fixed_log2_rows: None, pad: true } + } +} + +impl<'a, const DEGREE: usize> Poseidon2WideChip { + /// Transmute a row it to an immutable Poseidon2 instance. + pub(crate) fn convert(row: impl Deref) -> Box + 'a> + where + T: Copy + 'a, + { + if DEGREE == 3 { + let convert: &Poseidon2Degree3 = (*row).borrow(); + Box::new(*convert) + } else if DEGREE == 9 || DEGREE == 17 { + let convert: &Poseidon2Degree9 = (*row).borrow(); + Box::new(*convert) + } else { + panic!("Unsupported degree"); + } + } +} + +pub fn apply_m_4(x: &mut [AF]) +where + AF: AbstractField, +{ + let t01 = x[0].clone() + x[1].clone(); + let t23 = x[2].clone() + x[3].clone(); + let t0123 = t01.clone() + t23.clone(); + let t01123 = t0123.clone() + x[1].clone(); + let t01233 = t0123.clone() + x[3].clone(); + // The order here is important. Need to overwrite x[0] and x[2] after x[1] and x[3]. + x[3] = t01233.clone() + x[0].double(); // 3*x[0] + x[1] + x[2] + 2*x[3] + x[1] = t01123.clone() + x[2].double(); // x[0] + 2*x[1] + 3*x[2] + x[3] + x[0] = t01123 + t01; // 2*x[0] + 3*x[1] + x[2] + x[3] + x[2] = t01233 + t23; // x[0] + x[1] + 2*x[2] + 3*x[3] +} + +pub(crate) fn external_linear_layer(state: &mut [AF; WIDTH]) { + for j in (0..WIDTH).step_by(4) { + apply_m_4(&mut state[j..j + 4]); + } + let sums: [AF; 4] = + core::array::from_fn(|k| (0..WIDTH).step_by(4).map(|j| state[j + k].clone()).sum::()); + + for j in 0..WIDTH { + state[j] += sums[j % 4].clone(); + } +} + +pub(crate) fn external_linear_layer_immut( + state: &[AF; WIDTH], +) -> [AF; WIDTH] { + let mut state = *state; + external_linear_layer(&mut state); + state +} + +pub(crate) fn internal_linear_layer(state: &mut [F; WIDTH]) { + let matmul_constants: [::F; WIDTH] = + POSEIDON2_INTERNAL_MATRIX_DIAG_16_BABYBEAR_MONTY + .iter() + .map(|x| ::F::from_wrapped_u32(x.as_canonical_u32())) + .collect::>() + .try_into() + .unwrap(); + matmul_internal(state, matmul_constants); + let monty_inverse = F::from_wrapped_u32(MONTY_INVERSE.as_canonical_u32()); + state.iter_mut().for_each(|i| *i *= monty_inverse.clone()); +} + +#[cfg(test)] +pub(crate) mod tests { + + use std::{iter::once, sync::Arc}; + + use crate::{ + machine::RecursionAir, runtime::instruction as instr, MemAccessKind, RecursionProgram, + Runtime, + }; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_field::{AbstractField, PrimeField32}; + use p3_symmetric::Permutation; + + use sp1_core_machine::utils::{run_test_machine, setup_logger}; + use sp1_recursion_core::stark::config::BabyBearPoseidon2Outer; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, inner_perm, StarkGenericConfig}; + use zkhash::ark_ff::UniformRand; + + use super::WIDTH; + + #[test] + fn test_poseidon2() { + setup_logger(); + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + type EF = ::Challenge; + type A = RecursionAir; + type B = RecursionAir; + + let input = [1; WIDTH]; + let output = inner_perm() + .permute(input.map(BabyBear::from_canonical_u32)) + .map(|x| BabyBear::as_canonical_u32(&x)); + + let rng = &mut rand::thread_rng(); + let input_1: [BabyBear; WIDTH] = std::array::from_fn(|_| BabyBear::rand(rng)); + let output_1 = inner_perm().permute(input_1).map(|x| BabyBear::as_canonical_u32(&x)); + let input_1 = input_1.map(|x| BabyBear::as_canonical_u32(&x)); + + let instructions = + (0..WIDTH) + .map(|i| instr::mem(MemAccessKind::Write, 1, i as u32, input[i])) + .chain(once(instr::poseidon2( + [1; WIDTH], + std::array::from_fn(|i| (i + WIDTH) as u32), + std::array::from_fn(|i| i as u32), + ))) + .chain( + (0..WIDTH) + .map(|i| instr::mem(MemAccessKind::Read, 1, (i + WIDTH) as u32, output[i])), + ) + .chain((0..WIDTH).map(|i| { + instr::mem(MemAccessKind::Write, 1, (2 * WIDTH + i) as u32, input_1[i]) + })) + .chain(once(instr::poseidon2( + [1; WIDTH], + std::array::from_fn(|i| (i + 3 * WIDTH) as u32), + std::array::from_fn(|i| (i + 2 * WIDTH) as u32), + ))) + .chain((0..WIDTH).map(|i| { + instr::mem(MemAccessKind::Read, 1, (i + 3 * WIDTH) as u32, output_1[i]) + })) + .collect::>(); + + let program = Arc::new(RecursionProgram { instructions, ..Default::default() }); + let mut runtime = Runtime::::new( + program.clone(), + BabyBearPoseidon2::new().perm, + ); + runtime.run().unwrap(); + + let config = SC::new(); + let machine_deg_3 = A::machine_wide(config); + let (pk_3, vk_3) = machine_deg_3.setup(&program); + let result_deg_3 = + run_test_machine(vec![runtime.record.clone()], machine_deg_3, pk_3, vk_3); + if let Err(e) = result_deg_3 { + panic!("Verification failed: {:?}", e); + } + + let config = SC::new(); + let machine_deg_9 = B::machine_wide(config); + let (pk_9, vk_9) = machine_deg_9.setup(&program); + let result_deg_9 = run_test_machine(vec![runtime.record], machine_deg_9, pk_9, vk_9); + if let Err(e) = result_deg_9 { + panic!("Verification failed: {:?}", e); + } + } +} diff --git a/crates/recursion/core-v2/src/chips/poseidon2_wide/trace.rs b/crates/recursion/core-v2/src/chips/poseidon2_wide/trace.rs new file mode 100644 index 0000000000..bed204340d --- /dev/null +++ b/crates/recursion/core-v2/src/chips/poseidon2_wide/trace.rs @@ -0,0 +1,335 @@ +use std::{borrow::BorrowMut, mem::size_of}; + +use p3_air::BaseAir; +use p3_field::PrimeField32; +use p3_matrix::dense::RowMajorMatrix; +use p3_maybe_rayon::prelude::*; +use sp1_core_machine::utils::next_power_of_two; +use sp1_primitives::RC_16_30_U32; +use sp1_stark::air::MachineAir; +use tracing::instrument; + +#[cfg(debug_assertions)] +use p3_matrix::Matrix; + +use crate::{ + chips::{ + mem::MemoryAccessCols, + poseidon2_wide::{ + columns::permutation::permutation_mut, external_linear_layer_immut, Poseidon2WideChip, + NUM_EXTERNAL_ROUNDS, WIDTH, + }, + }, + instruction::Instruction::Poseidon2, + ExecutionRecord, RecursionProgram, +}; + +use super::{ + columns::preprocessed::Poseidon2PreprocessedCols, external_linear_layer, internal_linear_layer, + NUM_INTERNAL_ROUNDS, +}; + +const PREPROCESSED_POSEIDON2_WIDTH: usize = size_of::>(); + +impl MachineAir for Poseidon2WideChip { + type Record = ExecutionRecord; + + type Program = RecursionProgram; + + fn name(&self) -> String { + format!("Poseidon2WideDeg{}", DEGREE) + } + + #[instrument(name = "generate poseidon2 wide trace", level = "debug", skip_all, fields(rows = input.poseidon2_events.len()))] + fn generate_trace( + &self, + input: &ExecutionRecord, + _output: &mut ExecutionRecord, + ) -> RowMajorMatrix { + let events = &input.poseidon2_events; + let padded_nb_rows = next_power_of_two(events.len(), self.fixed_log2_rows); + let num_columns = >::width(self); + let mut values = vec![F::zero(); padded_nb_rows * num_columns]; + + let populate_len = events.len() * num_columns; + let (values_pop, values_dummy) = values.split_at_mut(populate_len); + join( + || { + values_pop.par_chunks_mut(num_columns).zip_eq(&input.poseidon2_events).for_each( + |(row, &event)| { + self.populate_perm(event.input, Some(event.output), row); + }, + ) + }, + || { + let mut dummy_row = vec![F::zero(); num_columns]; + self.populate_perm([F::zero(); WIDTH], None, &mut dummy_row); + values_dummy + .par_chunks_mut(num_columns) + .for_each(|row| row.copy_from_slice(&dummy_row)) + }, + ); + + // Convert the trace to a row major matrix. + let trace = RowMajorMatrix::new(values, num_columns); + + #[cfg(debug_assertions)] + println!( + "poseidon2 wide main trace dims is width: {:?}, height: {:?}", + trace.width(), + trace.height() + ); + + trace + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } + + fn preprocessed_width(&self) -> usize { + PREPROCESSED_POSEIDON2_WIDTH + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + // Allocating an intermediate `Vec` is faster. + let instrs = program + .instructions + .iter() // Faster than using `rayon` for some reason. Maybe vectorization? + .filter_map(|instruction| match instruction { + Poseidon2(instr) => Some(instr.as_ref()), + _ => None, + }) + .collect::>(); + + let padded_nb_rows = next_power_of_two(instrs.len(), self.fixed_log2_rows); + let mut values = vec![F::zero(); padded_nb_rows * PREPROCESSED_POSEIDON2_WIDTH]; + + let populate_len = instrs.len() * PREPROCESSED_POSEIDON2_WIDTH; + values[..populate_len] + .par_chunks_mut(PREPROCESSED_POSEIDON2_WIDTH) + .zip_eq(instrs) + .for_each(|(row, instr)| { + // Set the memory columns. We read once, at the first iteration, + // and write once, at the last iteration. + *row.borrow_mut() = Poseidon2PreprocessedCols { + input: instr.addrs.input, + output: std::array::from_fn(|j| MemoryAccessCols { + addr: instr.addrs.output[j], + mult: instr.mults[j], + }), + is_real_neg: F::neg_one(), + } + }); + Some(RowMajorMatrix::new(values, PREPROCESSED_POSEIDON2_WIDTH)) + } +} + +impl Poseidon2WideChip { + fn populate_perm( + &self, + input: [F; WIDTH], + expected_output: Option<[F; WIDTH]>, + input_row: &mut [F], + ) { + { + let permutation = permutation_mut::(input_row); + + let ( + external_rounds_state, + internal_rounds_state, + internal_rounds_s0, + mut external_sbox, + mut internal_sbox, + output_state, + ) = permutation.get_cols_mut(); + + external_rounds_state[0] = input; + + // Apply the first half of external rounds. + for r in 0..NUM_EXTERNAL_ROUNDS / 2 { + let next_state = + self.populate_external_round(external_rounds_state, &mut external_sbox, r); + if r == NUM_EXTERNAL_ROUNDS / 2 - 1 { + *internal_rounds_state = next_state; + } else { + external_rounds_state[r + 1] = next_state; + } + } + + // Apply the internal rounds. + external_rounds_state[NUM_EXTERNAL_ROUNDS / 2] = self.populate_internal_rounds( + internal_rounds_state, + internal_rounds_s0, + &mut internal_sbox, + ); + + // Apply the second half of external rounds. + for r in NUM_EXTERNAL_ROUNDS / 2..NUM_EXTERNAL_ROUNDS { + let next_state = + self.populate_external_round(external_rounds_state, &mut external_sbox, r); + if r == NUM_EXTERNAL_ROUNDS - 1 { + for i in 0..WIDTH { + output_state[i] = next_state[i]; + if let Some(expected_output) = expected_output { + assert_eq!(expected_output[i], next_state[i]); + } + } + } else { + external_rounds_state[r + 1] = next_state; + } + } + } + } + + fn populate_external_round( + &self, + external_rounds_state: &[[F; WIDTH]], + sbox: &mut Option<&mut [[F; WIDTH]; NUM_EXTERNAL_ROUNDS]>, + r: usize, + ) -> [F; WIDTH] { + let mut state = { + // For the first round, apply the linear layer. + let round_state: &[F; WIDTH] = if r == 0 { + &external_linear_layer_immut(&external_rounds_state[r]) + } else { + &external_rounds_state[r] + }; + + // Add round constants. + // + // Optimization: Since adding a constant is a degree 1 operation, we can avoid adding + // columns for it, and instead include it in the constraint for the x^3 part of the + // sbox. + let round = if r < NUM_EXTERNAL_ROUNDS / 2 { r } else { r + NUM_INTERNAL_ROUNDS }; + let mut add_rc = *round_state; + for i in 0..WIDTH { + add_rc[i] += F::from_wrapped_u32(RC_16_30_U32[round][i]); + } + + // Apply the sboxes. + // Optimization: since the linear layer that comes after the sbox is degree 1, we can + // avoid adding columns for the result of the sbox, and instead include the x^3 -> x^7 + // part of the sbox in the constraint for the linear layer + let mut sbox_deg_7: [F; 16] = [F::zero(); WIDTH]; + let mut sbox_deg_3: [F; 16] = [F::zero(); WIDTH]; + for i in 0..WIDTH { + sbox_deg_3[i] = add_rc[i] * add_rc[i] * add_rc[i]; + sbox_deg_7[i] = sbox_deg_3[i] * sbox_deg_3[i] * add_rc[i]; + } + + if let Some(sbox) = sbox.as_deref_mut() { + sbox[r] = sbox_deg_3; + } + + sbox_deg_7 + }; + + // Apply the linear layer. + external_linear_layer(&mut state); + state + } + + fn populate_internal_rounds( + &self, + internal_rounds_state: &[F; WIDTH], + internal_rounds_s0: &mut [F; NUM_INTERNAL_ROUNDS - 1], + sbox: &mut Option<&mut [F; NUM_INTERNAL_ROUNDS]>, + ) -> [F; WIDTH] { + let mut state: [F; WIDTH] = *internal_rounds_state; + let mut sbox_deg_3: [F; NUM_INTERNAL_ROUNDS] = [F::zero(); NUM_INTERNAL_ROUNDS]; + for r in 0..NUM_INTERNAL_ROUNDS { + // Add the round constant to the 0th state element. + // Optimization: Since adding a constant is a degree 1 operation, we can avoid adding + // columns for it, just like for external rounds. + let round = r + NUM_EXTERNAL_ROUNDS / 2; + let add_rc = state[0] + F::from_wrapped_u32(RC_16_30_U32[round][0]); + + // Apply the sboxes. + // Optimization: since the linear layer that comes after the sbox is degree 1, we can + // avoid adding columns for the result of the sbox, just like for external rounds. + sbox_deg_3[r] = add_rc * add_rc * add_rc; + let sbox_deg_7 = sbox_deg_3[r] * sbox_deg_3[r] * add_rc; + + // Apply the linear layer. + state[0] = sbox_deg_7; + internal_linear_layer(&mut state); + + // Optimization: since we're only applying the sbox to the 0th state element, we only + // need to have columns for the 0th state element at every step. This is because the + // linear layer is degree 1, so all state elements at the end can be expressed as a + // degree-3 polynomial of the state at the beginning of the internal rounds and the 0th + // state element at rounds prior to the current round + if r < NUM_INTERNAL_ROUNDS - 1 { + internal_rounds_s0[r] = state[0]; + } + } + + let ret_state = state; + + if let Some(sbox) = sbox.as_deref_mut() { + *sbox = sbox_deg_3; + } + + ret_state + } +} + +#[cfg(test)] +mod tests { + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + use p3_symmetric::Permutation; + use sp1_stark::{air::MachineAir, inner_perm}; + use zkhash::ark_ff::UniformRand; + + use crate::{ + chips::poseidon2_wide::{Poseidon2WideChip, WIDTH}, + ExecutionRecord, Poseidon2Event, + }; + + #[test] + fn generate_trace_deg_3() { + type F = BabyBear; + let input_0 = [F::one(); WIDTH]; + let permuter = inner_perm(); + let output_0 = permuter.permute(input_0); + let mut rng = rand::thread_rng(); + + let input_1 = [F::rand(&mut rng); WIDTH]; + let output_1 = permuter.permute(input_1); + + let shard = ExecutionRecord { + poseidon2_events: vec![ + Poseidon2Event { input: input_0, output: output_0 }, + Poseidon2Event { input: input_1, output: output_1 }, + ], + ..Default::default() + }; + let chip_3 = Poseidon2WideChip::<3>::default(); + let _: RowMajorMatrix = chip_3.generate_trace(&shard, &mut ExecutionRecord::default()); + } + + #[test] + fn generate_trace_deg_9() { + type F = BabyBear; + let input_0 = [F::one(); WIDTH]; + let permuter = inner_perm(); + let output_0 = permuter.permute(input_0); + let mut rng = rand::thread_rng(); + + let input_1 = [F::rand(&mut rng); WIDTH]; + let output_1 = permuter.permute(input_1); + + let shard = ExecutionRecord { + poseidon2_events: vec![ + Poseidon2Event { input: input_0, output: output_0 }, + Poseidon2Event { input: input_1, output: output_1 }, + ], + ..Default::default() + }; + let chip_9 = Poseidon2WideChip::<9>::default(); + let _: RowMajorMatrix = chip_9.generate_trace(&shard, &mut ExecutionRecord::default()); + } +} diff --git a/crates/recursion/core-v2/src/chips/public_values.rs b/crates/recursion/core-v2/src/chips/public_values.rs new file mode 100644 index 0000000000..b461cee328 --- /dev/null +++ b/crates/recursion/core-v2/src/chips/public_values.rs @@ -0,0 +1,242 @@ +use std::borrow::{Borrow, BorrowMut}; + +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; +use p3_field::PrimeField32; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_rows_fixed; +use sp1_derive::AlignedBorrow; +use sp1_recursion_core::air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; +use sp1_stark::air::MachineAir; + +use crate::{ + builder::SP1RecursionAirBuilder, + runtime::{Instruction, RecursionProgram}, + ExecutionRecord, +}; + +use crate::DIGEST_SIZE; + +use super::mem::MemoryAccessCols; + +pub const NUM_PUBLIC_VALUES_COLS: usize = core::mem::size_of::>(); +pub const NUM_PUBLIC_VALUES_PREPROCESSED_COLS: usize = + core::mem::size_of::>(); + +#[derive(Default)] +pub struct PublicValuesChip {} + +/// The preprocessed columns for the CommitPVHash instruction. +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct PublicValuesPreprocessedCols { + pub pv_idx: [T; DIGEST_SIZE], + pub pv_mem: MemoryAccessCols, +} + +/// The cols for a CommitPVHash invocation. +#[derive(AlignedBorrow, Debug, Clone, Copy)] +#[repr(C)] +pub struct PublicValuesCols { + pub pv_element: T, +} + +impl BaseAir for PublicValuesChip { + fn width(&self) -> usize { + NUM_PUBLIC_VALUES_COLS + } +} + +impl MachineAir for PublicValuesChip { + type Record = ExecutionRecord; + + type Program = RecursionProgram; + + fn name(&self) -> String { + "PublicValues".to_string() + } + + fn generate_dependencies(&self, _: &Self::Record, _: &mut Self::Record) { + // This is a no-op. + } + + fn preprocessed_width(&self) -> usize { + NUM_PUBLIC_VALUES_PREPROCESSED_COLS + } + + fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { + let mut rows: Vec<[F; NUM_PUBLIC_VALUES_PREPROCESSED_COLS]> = Vec::new(); + let commit_pv_hash_instrs = program + .instructions + .iter() + .filter_map(|instruction| { + if let Instruction::CommitPublicValues(instr) = instruction { + Some(instr) + } else { + None + } + }) + .collect::>(); + + if commit_pv_hash_instrs.len() != 1 { + tracing::warn!("Expected exactly one CommitPVHash instruction."); + } + + // We only take 1 commit pv hash instruction, since our air only checks for one public + // values hash. + for instr in commit_pv_hash_instrs.iter().take(1) { + for (i, addr) in instr.pv_addrs.digest.iter().enumerate() { + let mut row = [F::zero(); NUM_PUBLIC_VALUES_PREPROCESSED_COLS]; + let cols: &mut PublicValuesPreprocessedCols = row.as_mut_slice().borrow_mut(); + cols.pv_idx[i] = F::one(); + cols.pv_mem = MemoryAccessCols { addr: *addr, mult: F::neg_one() }; + rows.push(row); + } + } + + // Pad the preprocessed rows to 8 rows. + pad_rows_fixed(&mut rows, || [F::zero(); NUM_PUBLIC_VALUES_PREPROCESSED_COLS], Some(3)); + + let trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect(), + NUM_PUBLIC_VALUES_PREPROCESSED_COLS, + ); + Some(trace) + } + + fn generate_trace( + &self, + input: &ExecutionRecord, + _: &mut ExecutionRecord, + ) -> RowMajorMatrix { + if input.commit_pv_hash_events.len() != 1 { + tracing::warn!("Expected exactly one CommitPVHash event."); + } + + let mut rows: Vec<[F; NUM_PUBLIC_VALUES_COLS]> = Vec::new(); + + // We only take 1 commit pv hash instruction, since our air only checks for one public + // values hash. + for event in input.commit_pv_hash_events.iter().take(1) { + for element in event.public_values.digest.iter() { + let mut row = [F::zero(); NUM_PUBLIC_VALUES_COLS]; + let cols: &mut PublicValuesCols = row.as_mut_slice().borrow_mut(); + + cols.pv_element = *element; + rows.push(row); + } + } + + // Pad the trace to 8 rows. + pad_rows_fixed(&mut rows, || [F::zero(); NUM_PUBLIC_VALUES_COLS], Some(3)); + + // Convert the trace to a row major matrix. + RowMajorMatrix::new(rows.into_iter().flatten().collect(), NUM_PUBLIC_VALUES_COLS) + } + + fn included(&self, _record: &Self::Record) -> bool { + true + } +} + +impl Air for PublicValuesChip +where + AB: SP1RecursionAirBuilder + PairBuilder, +{ + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let local = main.row_slice(0); + let local: &PublicValuesCols = (*local).borrow(); + let prepr = builder.preprocessed(); + let local_prepr = prepr.row_slice(0); + let local_prepr: &PublicValuesPreprocessedCols = (*local_prepr).borrow(); + let pv = builder.public_values(); + let pv_elms: [AB::Expr; RECURSIVE_PROOF_NUM_PV_ELTS] = + core::array::from_fn(|i| pv[i].into()); + let public_values: &RecursionPublicValues = pv_elms.as_slice().borrow(); + + // Constrain mem read for the public value element. + builder.send_single(local_prepr.pv_mem.addr, local.pv_element, local_prepr.pv_mem.mult); + + for (i, pv_elm) in public_values.digest.iter().enumerate() { + // Ensure that the public value element is the same for all rows within a fri fold + // invocation. + builder.when(local_prepr.pv_idx[i]).assert_eq(pv_elm.clone(), local.pv_element); + } + } +} + +#[cfg(test)] +mod tests { + use rand::{rngs::StdRng, Rng, SeedableRng}; + use sp1_core_machine::utils::setup_logger; + use sp1_recursion_core::{ + air::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH, RECURSIVE_PROOF_NUM_PV_ELTS}, + stark::config::BabyBearPoseidon2Outer, + }; + use sp1_stark::{air::MachineAir, StarkGenericConfig}; + use std::{array, borrow::Borrow}; + + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use crate::{ + chips::public_values::PublicValuesChip, + machine::tests::run_recursion_test_machines, + runtime::{instruction as instr, ExecutionRecord}, + CommitPublicValuesEvent, MemAccessKind, RecursionProgram, DIGEST_SIZE, + }; + + #[test] + fn prove_babybear_circuit_public_values() { + setup_logger(); + type SC = BabyBearPoseidon2Outer; + type F = ::Val; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut random_felt = move || -> F { F::from_canonical_u32(rng.gen_range(0..1 << 16)) }; + let random_pv_elms: [F; RECURSIVE_PROOF_NUM_PV_ELTS] = array::from_fn(|_| random_felt()); + let addr = 0u32; + let public_values_a: [u32; RECURSIVE_PROOF_NUM_PV_ELTS] = + array::from_fn(|i| i as u32 + addr); + + let mut instructions = Vec::new(); + // Allocate the memory for the public values hash. + + for i in 0..RECURSIVE_PROOF_NUM_PV_ELTS { + let mult = (NUM_PV_ELMS_TO_HASH..NUM_PV_ELMS_TO_HASH + DIGEST_SIZE).contains(&i); + instructions.push(instr::mem_block( + MemAccessKind::Write, + mult as u32, + public_values_a[i], + random_pv_elms[i].into(), + )); + } + let public_values_a: &RecursionPublicValues = public_values_a.as_slice().borrow(); + instructions.push(instr::commit_public_values(public_values_a)); + + let program = RecursionProgram { instructions, ..Default::default() }; + + run_recursion_test_machines(program); + } + + #[test] + fn generate_public_values_circuit_trace() { + type F = BabyBear; + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let random_felts: [F; RECURSIVE_PROOF_NUM_PV_ELTS] = + array::from_fn(|_| F::from_canonical_u32(rng.gen_range(0..1 << 16))); + let random_public_values: &RecursionPublicValues = random_felts.as_slice().borrow(); + + let shard = ExecutionRecord { + commit_pv_hash_events: vec![CommitPublicValuesEvent { + public_values: *random_public_values, + }], + ..Default::default() + }; + let chip = PublicValuesChip::default(); + let trace: RowMajorMatrix = chip.generate_trace(&shard, &mut ExecutionRecord::default()); + println!("{:?}", trace.values) + } +} diff --git a/crates/recursion/core-v2/src/lib.rs b/crates/recursion/core-v2/src/lib.rs new file mode 100644 index 0000000000..61dd5cdc81 --- /dev/null +++ b/crates/recursion/core-v2/src/lib.rs @@ -0,0 +1,209 @@ +use std::iter::once; + +use p3_field::PrimeField64; +use serde::{Deserialize, Serialize}; +use sp1_derive::AlignedBorrow; +use sp1_recursion_core::air::{Block, RecursionPublicValues}; + +pub mod air; +pub mod builder; +pub mod chips; +pub mod machine; +pub mod runtime; + +pub use runtime::*; + +// Re-export the stark stuff from `sp1_recursion_core` for now, until we will migrate it here. +pub use sp1_recursion_core::stark; + +use crate::chips::poseidon2_skinny::WIDTH; + +#[derive( + AlignedBorrow, Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Default, +)] +#[repr(transparent)] +pub struct Address(pub F); + +impl Address { + #[inline] + pub fn as_usize(&self) -> usize { + self.0.as_canonical_u64() as usize + } +} + +// ------------------------------------------------------------------------------------------------- + +/// The inputs and outputs to an operation of the base field ALU. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[repr(C)] +pub struct BaseAluIo { + pub out: V, + pub in1: V, + pub in2: V, +} + +pub type BaseAluEvent = BaseAluIo; + +/// An instruction invoking the extension field ALU. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BaseAluInstr { + pub opcode: BaseAluOpcode, + pub mult: F, + pub addrs: BaseAluIo>, +} + +// ------------------------------------------------------------------------------------------------- + +/// The inputs and outputs to an operation of the extension field ALU. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[repr(C)] +pub struct ExtAluIo { + pub out: V, + pub in1: V, + pub in2: V, +} + +pub type ExtAluEvent = ExtAluIo>; + +/// An instruction invoking the extension field ALU. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExtAluInstr { + pub opcode: ExtAluOpcode, + pub mult: F, + pub addrs: ExtAluIo>, +} + +// ------------------------------------------------------------------------------------------------- + +/// The inputs and outputs to the manual memory management/memory initialization table. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct MemIo { + pub inner: V, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct MemInstr { + pub addrs: MemIo>, + pub vals: MemIo>, + pub mult: F, + pub kind: MemAccessKind, +} + +pub type MemEvent = MemIo>; + +// ------------------------------------------------------------------------------------------------- + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum MemAccessKind { + Read, + Write, +} + +/// The inputs and outputs to a Poseidon2 permutation. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Poseidon2Io { + pub input: [V; WIDTH], + pub output: [V; WIDTH], +} + +/// An instruction invoking the Poseidon2 permutation. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Poseidon2SkinnyInstr { + pub addrs: Poseidon2Io>, + pub mults: [F; WIDTH], +} + +pub type Poseidon2Event = Poseidon2Io; + +/// The inputs and outputs to an exp-reverse-bits operation. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct ExpReverseBitsIo { + pub base: V, + // The bits of the exponent in little-endian order in a vec. + pub exp: Vec, + pub result: V, +} + +pub type Poseidon2WideEvent = Poseidon2Io; +pub type Poseidon2Instr = Poseidon2SkinnyInstr; + +/// An instruction invoking the exp-reverse-bits operation. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExpReverseBitsInstr { + pub addrs: ExpReverseBitsIo>, + pub mult: F, +} + +/// The event encoding the inputs and outputs of an exp-reverse-bits operation. The `len` operand is +/// now stored as the length of the `exp` field. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct ExpReverseBitsEvent { + pub base: F, + pub exp: Vec, + pub result: F, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldIo { + pub ext_single: FriFoldExtSingleIo>, + pub ext_vec: FriFoldExtVecIo>>, + pub base_single: FriFoldBaseIo, +} + +/// The extension-field-valued single inputs to the FRI fold operation. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldExtSingleIo { + pub z: V, + pub alpha: V, +} + +/// The extension-field-valued vector inputs to the FRI fold operation. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldExtVecIo { + pub mat_opening: V, + pub ps_at_z: V, + pub alpha_pow_input: V, + pub ro_input: V, + pub alpha_pow_output: V, + pub ro_output: V, +} + +/// The base-field-valued inputs to the FRI fold operation. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldBaseIo { + pub x: V, +} + +/// An instruction invoking the FRI fold operation. Addresses for extension field elements are of +/// the same type as for base field elements. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldInstr { + pub base_single_addrs: FriFoldBaseIo>, + pub ext_single_addrs: FriFoldExtSingleIo>, + pub ext_vec_addrs: FriFoldExtVecIo>>, + pub alpha_pow_mults: Vec, + pub ro_mults: Vec, +} + +/// The event encoding the data of a single iteration within the FRI fold operation. +/// For any given event, we are accessing a single element of the `Vec` inputs, so that the event +/// is not a type alias for `FriFoldIo` like many of the other events. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FriFoldEvent { + pub base_single: FriFoldBaseIo, + pub ext_single: FriFoldExtSingleIo>, + pub ext_vec: FriFoldExtVecIo>, +} + +/// An instruction that will save the public values to the execution record and will commit to +/// it's digest. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CommitPublicValuesInstr { + pub pv_addrs: RecursionPublicValues>, +} + +/// The event for committing to the public values. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CommitPublicValuesEvent { + pub public_values: RecursionPublicValues, +} diff --git a/crates/recursion/core-v2/src/machine.rs b/crates/recursion/core-v2/src/machine.rs new file mode 100644 index 0000000000..a30a8846e9 --- /dev/null +++ b/crates/recursion/core-v2/src/machine.rs @@ -0,0 +1,325 @@ +use p3_field::{extension::BinomiallyExtendable, PrimeField32}; +use sp1_recursion_core::runtime::D; +use sp1_stark::{Chip, StarkGenericConfig, StarkMachine, PROOF_MAX_NUM_PVS}; + +use crate::chips::{ + alu_base::BaseAluChip, + alu_ext::ExtAluChip, + dummy::DummyChip, + exp_reverse_bits::ExpReverseBitsLenChip, + fri_fold::FriFoldChip, + mem::{MemoryConstChip, MemoryVarChip}, + poseidon2_skinny::Poseidon2SkinnyChip, + poseidon2_wide::Poseidon2WideChip, + public_values::PublicValuesChip, +}; + +#[derive(sp1_derive::MachineAir)] +#[sp1_core_path = "sp1_core_machine"] +#[execution_record_path = "crate::ExecutionRecord"] +#[program_path = "crate::RecursionProgram"] +#[builder_path = "crate::builder::SP1RecursionAirBuilder"] +#[eval_trait_bound = "AB::Var: 'static"] +pub enum RecursionAir< + F: PrimeField32 + BinomiallyExtendable, + const DEGREE: usize, + const COL_PADDING: usize, +> { + // Program(ProgramChip), + MemoryConst(MemoryConstChip), + MemoryVar(MemoryVarChip), + BaseAlu(BaseAluChip), + ExtAlu(ExtAluChip), + // Cpu(CpuChip), + // MemoryGlobal(MemoryGlobalChip), + Poseidon2Skinny(Poseidon2SkinnyChip), + Poseidon2Wide(Poseidon2WideChip), + FriFold(FriFoldChip), + // RangeCheck(RangeCheckChip), + // Multi(MultiChip), + ExpReverseBitsLen(ExpReverseBitsLenChip), + PublicValues(PublicValuesChip), + DummyWide(DummyChip), +} + +impl, const DEGREE: usize, const COL_PADDING: usize> + RecursionAir +{ + /// A recursion machine that can have dynamic trace sizes. + pub fn machine>(config: SC) -> StarkMachine { + let chips = Self::get_all().into_iter().map(Chip::new).collect::>(); + StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) + } + + /// A recursion machine that can have dynamic trace sizes, and uses the wide variant of + /// Poseidon2. + pub fn machine_wide>(config: SC) -> StarkMachine { + let chips = Self::get_all_wide().into_iter().map(Chip::new).collect::>(); + StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) + } + + pub fn machine_with_padding>( + config: SC, + fri_fold_padding: usize, + poseidon2_padding: usize, + erbl_padding: usize, + ) -> StarkMachine { + let chips = Self::get_all_with_padding(fri_fold_padding, poseidon2_padding, erbl_padding) + .into_iter() + .map(Chip::new) + .collect::>(); + StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) + } + + pub fn dummy_machine>( + config: SC, + log_height: usize, + ) -> StarkMachine { + let chips = vec![RecursionAir::DummyWide(DummyChip::new(log_height))]; + StarkMachine::new(config, chips.into_iter().map(Chip::new).collect(), PROOF_MAX_NUM_PVS) + } + // /// A recursion machine with fixed trace sizes tuned to work specifically for the wrap layer. + // pub fn wrap_machine>(config: SC) -> StarkMachine { + // let chips = Self::get_wrap_all() + // .into_iter() + // .map(Chip::new) + // .collect::>(); + // StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) + // } + + // /// A recursion machine with fixed trace sizes tuned to work specifically for the wrap layer. + // pub fn wrap_machine_dyn>(config: SC) -> StarkMachine { let chips = Self::get_wrap_dyn_all() + // .into_iter() + // .map(Chip::new) + // .collect::>(); + // StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) + // } + + pub fn get_all() -> Vec { + vec![ + RecursionAir::MemoryConst(MemoryConstChip::default()), + RecursionAir::MemoryVar(MemoryVarChip::default()), + RecursionAir::BaseAlu(BaseAluChip::default()), + RecursionAir::ExtAlu(ExtAluChip::default()), + RecursionAir::Poseidon2Skinny(Poseidon2SkinnyChip::::default()), + // RecursionAir::Poseidon2Wide(Poseidon2WideChip::::default()), + RecursionAir::ExpReverseBitsLen(ExpReverseBitsLenChip::::default()), + RecursionAir::FriFold(FriFoldChip::::default()), + RecursionAir::PublicValues(PublicValuesChip::default()), + ] + } + + pub fn get_all_wide() -> Vec { + vec![ + // RecursionAir::Program(ProgramChip::default()), + RecursionAir::MemoryConst(MemoryConstChip::default()), + RecursionAir::MemoryVar(MemoryVarChip::default()), + RecursionAir::BaseAlu(BaseAluChip::default()), + RecursionAir::ExtAlu(ExtAluChip::default()), + // RecursionAir::Poseidon2Skinny(Poseidon2SkinnyChip::::default()), + RecursionAir::Poseidon2Wide(Poseidon2WideChip::::default()), + RecursionAir::ExpReverseBitsLen(ExpReverseBitsLenChip::::default()), + RecursionAir::FriFold(FriFoldChip::::default()), + RecursionAir::PublicValues(PublicValuesChip::default()), + ] + } + + pub fn get_all_with_padding( + fri_fold_padding: usize, + poseidon2_padding: usize, + erbl_padding: usize, + ) -> Vec { + vec![ + // RecursionAir::Program(ProgramChip::default()), + RecursionAir::MemoryConst(MemoryConstChip::default()), + RecursionAir::MemoryVar(MemoryVarChip::default()), + RecursionAir::BaseAlu(BaseAluChip::default()), + RecursionAir::ExtAlu(ExtAluChip::default()), + // RecursionAir::Poseidon2Wide(Poseidon2WideChip::::default()), + RecursionAir::Poseidon2Skinny(Poseidon2SkinnyChip:: { + fixed_log2_rows: Some(poseidon2_padding), + pad: true, + }), + RecursionAir::ExpReverseBitsLen(ExpReverseBitsLenChip:: { + fixed_log2_rows: Some(erbl_padding), + pad: true, + }), + RecursionAir::FriFold(FriFoldChip:: { + fixed_log2_rows: Some(fri_fold_padding), + pad: true, + }), + RecursionAir::PublicValues(PublicValuesChip::default()), + ] + } + + // pub fn get_wrap_dyn_all() -> Vec { + // once(RecursionAir::Program(ProgramChip)) + // .chain(once(RecursionAir::Cpu(CpuChip { + // fixed_log2_rows: None, + // _phantom: PhantomData, + // }))) + // .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { + // fixed_log2_rows: None, + // }))) + // .chain(once(RecursionAir::Multi(MultiChip { + // fixed_log2_rows: None, + // }))) + // .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) + // .chain(once(RecursionAir::ExpReverseBitsLen( + // ExpReverseBitsLenChip:: { + // fixed_log2_rows: None, + // pad: true, + // }, + // ))) + // .collect() + // } + + // pub fn get_wrap_all() -> Vec { + // once(RecursionAir::Program(ProgramChip)) + // .chain(once(RecursionAir::Cpu(CpuChip { + // fixed_log2_rows: Some(19), + // _phantom: PhantomData, + // }))) + // .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { + // fixed_log2_rows: Some(20), + // }))) + // .chain(once(RecursionAir::Multi(MultiChip { + // fixed_log2_rows: Some(17), + // }))) + // .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) + // .chain(once(RecursionAir::ExpReverseBitsLen( + // ExpReverseBitsLenChip:: { + // fixed_log2_rows: None, + // pad: true, + // }, + // ))) + // .collect() + // } +} + +#[cfg(test)] +pub mod tests { + + use std::sync::Arc; + + use machine::RecursionAir; + use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_field::{ + extension::{BinomialExtensionField, HasFrobenius}, + AbstractExtensionField, AbstractField, Field, + }; + use rand::prelude::*; + use sp1_core_machine::utils::run_test_machine; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; + + // TODO expand glob import + use crate::{runtime::instruction as instr, *}; + + type SC = BabyBearPoseidon2; + type F = ::Val; + type EF = ::Challenge; + type A = RecursionAir; + type B = RecursionAir; + + /// Runs the given program on machines that use the wide and skinny Poseidon2 chips. + pub fn run_recursion_test_machines(program: RecursionProgram) { + let program = Arc::new(program); + let mut runtime = + Runtime::::new(program.clone(), SC::new().perm); + runtime.run().unwrap(); + + // Run with the poseidon2 wide chip. + let wide_machine = A::machine_wide(BabyBearPoseidon2::default()); + let (pk, vk) = wide_machine.setup(&program); + let result = run_test_machine(vec![runtime.record.clone()], wide_machine, pk, vk); + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + + // Run with the poseidon2 skinny chip. + let skinny_machine = B::machine(BabyBearPoseidon2::compressed()); + let (pk, vk) = skinny_machine.setup(&program); + let result = run_test_machine(vec![runtime.record], skinny_machine, pk, vk); + if let Err(e) = result { + panic!("Verification failed: {:?}", e); + } + } + + fn test_instructions(instructions: Vec>) { + let program = RecursionProgram { instructions, ..Default::default() }; + run_recursion_test_machines(program); + } + + #[test] + pub fn fibonacci() { + let n = 10; + + let instructions = once(instr::mem(MemAccessKind::Write, 1, 0, 0)) + .chain(once(instr::mem(MemAccessKind::Write, 2, 1, 1))) + .chain((2..=n).map(|i| instr::base_alu(BaseAluOpcode::AddF, 2, i, i - 2, i - 1))) + .chain(once(instr::mem(MemAccessKind::Read, 1, n - 1, 34))) + .chain(once(instr::mem(MemAccessKind::Read, 2, n, 55))) + .collect::>(); + + test_instructions(instructions); + } + + #[test] + #[should_panic] + pub fn div_nonzero_by_zero() { + let instructions = vec![ + instr::mem(MemAccessKind::Write, 1, 0, 0), + instr::mem(MemAccessKind::Write, 1, 1, 1), + instr::base_alu(BaseAluOpcode::DivF, 1, 2, 1, 0), + instr::mem(MemAccessKind::Read, 1, 2, 1), + ]; + + test_instructions(instructions); + } + + #[test] + pub fn div_zero_by_zero() { + let instructions = vec![ + instr::mem(MemAccessKind::Write, 1, 0, 0), + instr::mem(MemAccessKind::Write, 1, 1, 0), + instr::base_alu(BaseAluOpcode::DivF, 1, 2, 1, 0), + instr::mem(MemAccessKind::Read, 1, 2, 1), + ]; + + test_instructions(instructions); + } + + #[test] + pub fn field_norm() { + let mut instructions = Vec::new(); + + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); + let mut addr = 0; + for _ in 0..100 { + let inner: [F; 4] = std::iter::repeat_with(|| { + core::array::from_fn(|_| rng.sample(rand::distributions::Standard)) + }) + .find(|xs| !xs.iter().all(F::is_zero)) + .unwrap(); + let x = BinomialExtensionField::::from_base_slice(&inner); + let gal = x.galois_group(); + + let mut acc = BinomialExtensionField::one(); + + instructions.push(instr::mem_ext(MemAccessKind::Write, 1, addr, acc)); + for conj in gal { + instructions.push(instr::mem_ext(MemAccessKind::Write, 1, addr + 1, conj)); + instructions.push(instr::ext_alu(ExtAluOpcode::MulE, 1, addr + 2, addr, addr + 1)); + + addr += 2; + acc *= conj; + } + let base_cmp: F = acc.as_base_slice()[0]; + instructions.push(instr::mem_single(MemAccessKind::Read, 1, addr, base_cmp)); + addr += 1; + } + + test_instructions(instructions); + } +} diff --git a/crates/recursion/core-v2/src/runtime/instruction.rs b/crates/recursion/core-v2/src/runtime/instruction.rs new file mode 100644 index 0000000000..a565cf9e34 --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/instruction.rs @@ -0,0 +1,215 @@ +use std::borrow::Borrow; + +use p3_field::{AbstractExtensionField, AbstractField}; +use serde::{Deserialize, Serialize}; + +use crate::*; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Instruction { + BaseAlu(BaseAluInstr), + ExtAlu(ExtAluInstr), + Mem(MemInstr), + Poseidon2(Box>), + ExpReverseBitsLen(ExpReverseBitsInstr), + HintBits(HintBitsInstr), + FriFold(Box>), + Print(PrintInstr), + HintExt2Felts(HintExt2FeltsInstr), + CommitPublicValues(Box>), + Hint(HintInstr), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct HintBitsInstr { + /// Addresses and mults of the output bits. + pub output_addrs_mults: Vec<(Address, F)>, + /// Input value to decompose. + pub input_addr: Address, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PrintInstr { + pub field_elt_type: FieldEltType, + pub addr: Address, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct HintInstr { + /// Addresses and mults of the output felts. + pub output_addrs_mults: Vec<(Address, F)>, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct HintExt2FeltsInstr { + /// Addresses and mults of the output bits. + pub output_addrs_mults: [(Address, F); D], + /// Input value to decompose. + pub input_addr: Address, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum FieldEltType { + Base, + Extension, +} + +pub fn base_alu( + opcode: BaseAluOpcode, + mult: u32, + out: u32, + in1: u32, + in2: u32, +) -> Instruction { + Instruction::BaseAlu(BaseAluInstr { + opcode, + mult: F::from_canonical_u32(mult), + addrs: BaseAluIo { + out: Address(F::from_canonical_u32(out)), + in1: Address(F::from_canonical_u32(in1)), + in2: Address(F::from_canonical_u32(in2)), + }, + }) +} + +pub fn ext_alu( + opcode: ExtAluOpcode, + mult: u32, + out: u32, + in1: u32, + in2: u32, +) -> Instruction { + Instruction::ExtAlu(ExtAluInstr { + opcode, + mult: F::from_canonical_u32(mult), + addrs: ExtAluIo { + out: Address(F::from_canonical_u32(out)), + in1: Address(F::from_canonical_u32(in1)), + in2: Address(F::from_canonical_u32(in2)), + }, + }) +} + +pub fn mem( + kind: MemAccessKind, + mult: u32, + addr: u32, + val: u32, +) -> Instruction { + mem_single(kind, mult, addr, F::from_canonical_u32(val)) +} + +pub fn mem_single( + kind: MemAccessKind, + mult: u32, + addr: u32, + val: F, +) -> Instruction { + mem_block(kind, mult, addr, Block::from(val)) +} + +pub fn mem_ext>( + kind: MemAccessKind, + mult: u32, + addr: u32, + val: EF, +) -> Instruction { + mem_block(kind, mult, addr, val.as_base_slice().into()) +} + +pub fn mem_block( + kind: MemAccessKind, + mult: u32, + addr: u32, + val: Block, +) -> Instruction { + Instruction::Mem(MemInstr { + addrs: MemIo { inner: Address(F::from_canonical_u32(addr)) }, + vals: MemIo { inner: val }, + mult: F::from_canonical_u32(mult), + kind, + }) +} + +pub fn poseidon2( + mults: [u32; WIDTH], + output: [u32; WIDTH], + input: [u32; WIDTH], +) -> Instruction { + Instruction::Poseidon2(Box::new(Poseidon2Instr { + mults: mults.map(F::from_canonical_u32), + addrs: Poseidon2Io { + output: output.map(F::from_canonical_u32).map(Address), + input: input.map(F::from_canonical_u32).map(Address), + }, + })) +} + +pub fn exp_reverse_bits_len( + mult: u32, + base: F, + exp: Vec, + result: F, +) -> Instruction { + Instruction::ExpReverseBitsLen(ExpReverseBitsInstr { + mult: F::from_canonical_u32(mult), + addrs: ExpReverseBitsIo { + base: Address(base), + exp: exp.into_iter().map(Address).collect(), + result: Address(result), + }, + }) +} + +#[allow(clippy::too_many_arguments)] +pub fn fri_fold( + z: u32, + alpha: u32, + x: u32, + mat_opening: Vec, + ps_at_z: Vec, + alpha_pow_input: Vec, + ro_input: Vec, + alpha_pow_output: Vec, + ro_output: Vec, + alpha_mults: Vec, + ro_mults: Vec, +) -> Instruction { + Instruction::FriFold(Box::new(FriFoldInstr { + base_single_addrs: FriFoldBaseIo { x: Address(F::from_canonical_u32(x)) }, + ext_single_addrs: FriFoldExtSingleIo { + z: Address(F::from_canonical_u32(z)), + alpha: Address(F::from_canonical_u32(alpha)), + }, + ext_vec_addrs: FriFoldExtVecIo { + mat_opening: mat_opening + .iter() + .map(|elm| Address(F::from_canonical_u32(*elm))) + .collect(), + ps_at_z: ps_at_z.iter().map(|elm| Address(F::from_canonical_u32(*elm))).collect(), + alpha_pow_input: alpha_pow_input + .iter() + .map(|elm| Address(F::from_canonical_u32(*elm))) + .collect(), + ro_input: ro_input.iter().map(|elm| Address(F::from_canonical_u32(*elm))).collect(), + alpha_pow_output: alpha_pow_output + .iter() + .map(|elm| Address(F::from_canonical_u32(*elm))) + .collect(), + ro_output: ro_output.iter().map(|elm| Address(F::from_canonical_u32(*elm))).collect(), + }, + alpha_pow_mults: alpha_mults.iter().map(|mult| F::from_canonical_u32(*mult)).collect(), + ro_mults: ro_mults.iter().map(|mult| F::from_canonical_u32(*mult)).collect(), + })) +} + +pub fn commit_public_values( + public_values_a: &RecursionPublicValues, +) -> Instruction { + let pv_a = public_values_a.to_vec().map(|pv| Address(F::from_canonical_u32(pv))); + let pv_address: &RecursionPublicValues> = pv_a.as_slice().borrow(); + + Instruction::CommitPublicValues(Box::new(CommitPublicValuesInstr { + pv_addrs: pv_address.clone(), + })) +} diff --git a/crates/recursion/core-v2/src/runtime/memory.rs b/crates/recursion/core-v2/src/runtime/memory.rs new file mode 100644 index 0000000000..89cc829ec3 --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/memory.rs @@ -0,0 +1,108 @@ +use std::iter::repeat; + +use p3_field::PrimeField64; +use sp1_recursion_core::air::Block; +use vec_map::{Entry, VecMap}; + +use crate::Address; + +#[derive(Debug, Clone, Default)] +pub struct MemoryEntry { + pub val: Block, + pub mult: F, +} + +pub trait Memory { + /// Allocates memory with at least the given capacity. + fn with_capacity(capacity: usize) -> Self; + + /// Read from a memory address. Decrements the memory entry's mult count. + /// + /// # Panics + /// Panics if the address is unassigned. + fn mr(&mut self, addr: Address) -> &mut MemoryEntry; + + /// Read from a memory address. Reduces the memory entry's mult count by the given amount. + /// + /// # Panics + /// Panics if the address is unassigned. + fn mr_mult(&mut self, addr: Address, mult: F) -> &mut MemoryEntry; + + /// Write to a memory address, setting the given value and mult. + /// + /// # Panics + /// Panics if the address is already assigned. + fn mw(&mut self, addr: Address, val: Block, mult: F) -> &mut MemoryEntry; +} + +#[derive(Clone, Debug, Default)] +pub struct MemVecMap(pub VecMap>); + +impl Memory for MemVecMap { + fn with_capacity(capacity: usize) -> Self { + Self(VecMap::with_capacity(capacity)) + } + + fn mr(&mut self, addr: Address) -> &mut MemoryEntry { + self.mr_mult(addr, F::one()) + } + + fn mr_mult(&mut self, addr: Address, mult: F) -> &mut MemoryEntry { + match self.0.entry(addr.as_usize()) { + Entry::Occupied(mut entry) => { + let entry_mult = &mut entry.get_mut().mult; + *entry_mult -= mult; + entry.into_mut() + } + Entry::Vacant(_) => panic!("tried to read from unassigned address: {addr:?}",), + } + } + + fn mw(&mut self, addr: Address, val: Block, mult: F) -> &mut MemoryEntry { + let index = addr.as_usize(); + match self.0.entry(index) { + Entry::Occupied(entry) => { + panic!("tried to write to assigned address {}: {:?}", index, entry.get()) + } + Entry::Vacant(entry) => entry.insert(MemoryEntry { val, mult }), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct MemVec(pub Vec>>); + +impl Memory for MemVec { + fn with_capacity(capacity: usize) -> Self { + Self(Vec::with_capacity(capacity)) + } + + fn mr(&mut self, addr: Address) -> &mut MemoryEntry { + self.mr_mult(addr, F::one()) + } + + fn mr_mult(&mut self, addr: Address, mult: F) -> &mut MemoryEntry { + match self.0.get_mut(addr.as_usize()) { + Some(Some(entry)) => { + entry.mult -= mult; + entry + } + _ => panic!( + "tried to read from unassigned address: {addr:?}\nbacktrace: {:?}", + backtrace::Backtrace::new() + ), + } + } + + fn mw(&mut self, addr: Address, val: Block, mult: F) -> &mut MemoryEntry { + let addr_usize = addr.as_usize(); + self.0.extend(repeat(None).take((addr_usize + 1).saturating_sub(self.0.len()))); + match &mut self.0[addr_usize] { + Some(entry) => panic!( + "tried to write to assigned address: {entry:?}\nbacktrace: {:?}", + backtrace::Backtrace::new() + ), + entry @ None => entry.insert(MemoryEntry { val, mult }), + } + } +} diff --git a/crates/recursion/core-v2/src/runtime/mod.rs b/crates/recursion/core-v2/src/runtime/mod.rs new file mode 100644 index 0000000000..296517397e --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/mod.rs @@ -0,0 +1,523 @@ +pub mod instruction; +mod memory; +mod opcode; +mod program; +mod record; + +// Avoid triggering annoying branch of thiserror derive macro. +use backtrace::Backtrace as Trace; +pub use instruction::Instruction; +use instruction::{FieldEltType, HintBitsInstr, HintExt2FeltsInstr, HintInstr, PrintInstr}; +use memory::*; +pub use opcode::*; +pub use program::*; +pub use record::*; + +use std::{ + array, + borrow::Borrow, + collections::VecDeque, + fmt::Debug, + io::{stdout, Write}, + iter::zip, + marker::PhantomData, + sync::Arc, +}; + +use hashbrown::HashMap; +use itertools::Itertools; +use p3_field::{AbstractField, ExtensionField, PrimeField32}; +use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +use p3_symmetric::{CryptographicPermutation, Permutation}; +use p3_util::reverse_bits_len; +use thiserror::Error; + +use sp1_recursion_core::air::{Block, RECURSIVE_PROOF_NUM_PV_ELTS}; + +/// TODO expand glob import once things are organized enough +use crate::*; + +/// The heap pointer address. +pub const HEAP_PTR: i32 = -4; +pub const HEAP_START_ADDRESS: usize = STACK_SIZE + 4; + +pub const STACK_SIZE: usize = 1 << 24; +pub const MEMORY_SIZE: usize = 1 << 28; + +/// The width of the Poseidon2 permutation. +pub const PERMUTATION_WIDTH: usize = 16; +pub const POSEIDON2_SBOX_DEGREE: u64 = 7; +pub const HASH_RATE: usize = 8; + +/// The current verifier implementation assumes that we are using a 256-bit hash with 32-bit +/// elements. +pub const DIGEST_SIZE: usize = 8; + +pub const NUM_BITS: usize = 31; + +pub const D: usize = 4; + +#[derive(Debug, Clone, Default)] +pub struct CycleTrackerEntry { + pub span_entered: bool, + pub span_enter_cycle: usize, + pub cumulative_cycles: usize, +} + +/// TODO fully document. +/// Taken from [`sp1_recursion_core::runtime::Runtime`]. +/// Many missing things (compared to the old `Runtime`) will need to be implemented. +pub struct Runtime<'a, F: PrimeField32, EF: ExtensionField, Diffusion> { + pub timestamp: usize, + + pub nb_poseidons: usize, + + pub nb_wide_poseidons: usize, + + pub nb_bit_decompositions: usize, + + pub nb_ext_ops: usize, + + pub nb_base_ops: usize, + + pub nb_memory_ops: usize, + + pub nb_branch_ops: usize, + + pub nb_exp_reverse_bits: usize, + + pub nb_fri_fold: usize, + + pub nb_print_f: usize, + + pub nb_print_e: usize, + + /// The current clock. + pub clk: F, + + /// The program counter. + pub pc: F, + + /// The program. + pub program: Arc>, + + /// Memory. From canonical usize of an Address to a MemoryEntry. + pub memory: MemVecMap, + + /// The execution record. + pub record: ExecutionRecord, + + pub witness_stream: VecDeque>, + + pub cycle_tracker: HashMap, + + /// The stream that print statements write to. + pub debug_stdout: Box, + + /// Entries for dealing with the Poseidon2 hash state. + perm: Option< + Poseidon2< + F, + Poseidon2ExternalMatrixGeneral, + Diffusion, + PERMUTATION_WIDTH, + POSEIDON2_SBOX_DEGREE, + >, + >, + + _marker_ef: PhantomData, + + _marker_diffusion: PhantomData, +} + +#[derive(Error, Debug)] +pub enum RuntimeError { + #[error( + "attempted to perform base field division {in1:?}/{in2:?} \ + from instruction {instr:?} at pc {pc:?}\nnearest pc with backtrace:\n{trace:?}" + )] + DivFOutOfDomain { + in1: F, + in2: F, + instr: BaseAluInstr, + pc: usize, + trace: Option<(usize, Trace)>, + }, + #[error( + "attempted to perform extension field division {in1:?}/{in2:?} \ + from instruction {instr:?} at pc {pc:?}\nnearest pc with backtrace:\n{trace:?}" + )] + DivEOutOfDomain { + in1: EF, + in2: EF, + instr: ExtAluInstr, + pc: usize, + trace: Option<(usize, Trace)>, + }, + #[error("failed to print to `debug_stdout`: {0}")] + DebugPrint(#[from] std::io::Error), + #[error("attempted to read from empty witness stream")] + EmptyWitnessStream, +} + +impl<'a, F: PrimeField32, EF: ExtensionField, Diffusion> Runtime<'a, F, EF, Diffusion> +where + Poseidon2< + F, + Poseidon2ExternalMatrixGeneral, + Diffusion, + PERMUTATION_WIDTH, + POSEIDON2_SBOX_DEGREE, + >: CryptographicPermutation<[F; PERMUTATION_WIDTH]>, +{ + pub fn new( + program: Arc>, + perm: Poseidon2< + F, + Poseidon2ExternalMatrixGeneral, + Diffusion, + PERMUTATION_WIDTH, + POSEIDON2_SBOX_DEGREE, + >, + ) -> Self { + let record = ExecutionRecord:: { program: program.clone(), ..Default::default() }; + let memory = Memory::with_capacity(program.total_memory); + Self { + timestamp: 0, + nb_poseidons: 0, + nb_wide_poseidons: 0, + nb_bit_decompositions: 0, + nb_exp_reverse_bits: 0, + nb_ext_ops: 0, + nb_base_ops: 0, + nb_memory_ops: 0, + nb_branch_ops: 0, + nb_fri_fold: 0, + nb_print_f: 0, + nb_print_e: 0, + clk: F::zero(), + program, + pc: F::zero(), + memory, + record, + witness_stream: VecDeque::new(), + cycle_tracker: HashMap::new(), + debug_stdout: Box::new(stdout()), + perm: Some(perm), + _marker_ef: PhantomData, + _marker_diffusion: PhantomData, + } + } + + pub fn print_stats(&self) { + tracing::debug!("Total Cycles: {}", self.timestamp); + tracing::debug!("Poseidon Skinny Operations: {}", self.nb_poseidons); + tracing::debug!("Poseidon Wide Operations: {}", self.nb_wide_poseidons); + tracing::debug!("Exp Reverse Bits Operations: {}", self.nb_exp_reverse_bits); + tracing::debug!("FriFold Operations: {}", self.nb_fri_fold); + tracing::debug!("Field Operations: {}", self.nb_base_ops); + tracing::debug!("Extension Operations: {}", self.nb_ext_ops); + tracing::debug!("Memory Operations: {}", self.nb_memory_ops); + tracing::debug!("Branch Operations: {}", self.nb_branch_ops); + for (name, entry) in self.cycle_tracker.iter().sorted_by_key(|(name, _)| *name) { + tracing::debug!("> {}: {}", name, entry.cumulative_cycles); + } + } + + fn nearest_pc_backtrace(&mut self) -> Option<(usize, Trace)> { + let trap_pc = self.pc.as_canonical_u32() as usize; + let trace = self.program.traces[trap_pc].clone(); + if let Some(mut trace) = trace { + trace.resolve(); + Some((trap_pc, trace)) + } else { + (0..trap_pc) + .rev() + .filter_map(|nearby_pc| { + let mut trace = self.program.traces.get(nearby_pc)?.clone()?; + trace.resolve(); + Some((nearby_pc, trace)) + }) + .next() + } + } + + /// Compare to [sp1_recursion_core::runtime::Runtime::run]. + pub fn run(&mut self) -> Result<(), RuntimeError> { + let early_exit_ts = std::env::var("RECURSION_EARLY_EXIT_TS") + .map_or(usize::MAX, |ts: String| ts.parse().unwrap()); + while self.pc < F::from_canonical_u32(self.program.instructions.len() as u32) { + let idx = self.pc.as_canonical_u32() as usize; + let instruction = self.program.instructions[idx].clone(); + + let next_clk = self.clk + F::from_canonical_u32(4); + let next_pc = self.pc + F::one(); + match instruction { + Instruction::BaseAlu(instr @ BaseAluInstr { opcode, mult, addrs }) => { + self.nb_base_ops += 1; + let in1 = self.memory.mr(addrs.in1).val[0]; + let in2 = self.memory.mr(addrs.in2).val[0]; + // Do the computation. + let out = match opcode { + BaseAluOpcode::AddF => in1 + in2, + BaseAluOpcode::SubF => in1 - in2, + BaseAluOpcode::MulF => in1 * in2, + BaseAluOpcode::DivF => match in1.try_div(in2) { + Some(x) => x, + None => { + // Check for division exceptions and error. Note that 0/0 is defined + // to be 1. + if in1.is_zero() { + AbstractField::one() + } else { + return Err(RuntimeError::DivFOutOfDomain { + in1, + in2, + instr, + pc: self.pc.as_canonical_u32() as usize, + trace: self.nearest_pc_backtrace(), + }); + } + } + }, + }; + self.memory.mw(addrs.out, Block::from(out), mult); + self.record.base_alu_events.push(BaseAluEvent { out, in1, in2 }); + } + Instruction::ExtAlu(instr @ ExtAluInstr { opcode, mult, addrs }) => { + self.nb_ext_ops += 1; + let in1 = self.memory.mr(addrs.in1).val; + let in2 = self.memory.mr(addrs.in2).val; + // Do the computation. + let in1_ef = EF::from_base_slice(&in1.0); + let in2_ef = EF::from_base_slice(&in2.0); + let out_ef = match opcode { + ExtAluOpcode::AddE => in1_ef + in2_ef, + ExtAluOpcode::SubE => in1_ef - in2_ef, + ExtAluOpcode::MulE => in1_ef * in2_ef, + ExtAluOpcode::DivE => match in1_ef.try_div(in2_ef) { + Some(x) => x, + None => { + // Check for division exceptions and error. Note that 0/0 is defined + // to be 1. + if in1_ef.is_zero() { + AbstractField::one() + } else { + return Err(RuntimeError::DivEOutOfDomain { + in1: in1_ef, + in2: in2_ef, + instr, + pc: self.pc.as_canonical_u32() as usize, + trace: self.nearest_pc_backtrace(), + }); + } + } + }, + }; + let out = Block::from(out_ef.as_base_slice()); + self.memory.mw(addrs.out, out, mult); + self.record.ext_alu_events.push(ExtAluEvent { out, in1, in2 }); + } + Instruction::Mem(MemInstr { + addrs: MemIo { inner: addr }, + vals: MemIo { inner: val }, + mult, + kind, + }) => { + self.nb_memory_ops += 1; + match kind { + MemAccessKind::Read => { + let mem_entry = self.memory.mr_mult(addr, mult); + assert_eq!( + mem_entry.val, val, + "stored memory value should be the specified value" + ); + } + MemAccessKind::Write => drop(self.memory.mw(addr, val, mult)), + } + self.record.mem_const_count += 1; + } + Instruction::Poseidon2(instr) => { + let Poseidon2Instr { addrs: Poseidon2Io { input, output }, mults } = *instr; + self.nb_poseidons += 1; + let in_vals = std::array::from_fn(|i| self.memory.mr(input[i]).val[0]); + let perm_output = self.perm.as_ref().unwrap().permute(in_vals); + + perm_output.iter().zip(output).zip(mults).for_each(|((&val, addr), mult)| { + self.memory.mw(addr, Block::from(val), mult); + }); + self.record + .poseidon2_events + .push(Poseidon2Event { input: in_vals, output: perm_output }); + } + Instruction::ExpReverseBitsLen(ExpReverseBitsInstr { + addrs: ExpReverseBitsIo { base, exp, result }, + mult, + }) => { + self.nb_exp_reverse_bits += 1; + let base_val = self.memory.mr(base).val[0]; + let exp_bits: Vec<_> = + exp.iter().map(|bit| self.memory.mr(*bit).val[0]).collect(); + let exp_val = exp_bits + .iter() + .enumerate() + .fold(0, |acc, (i, &val)| acc + val.as_canonical_u32() * (1 << i)); + let out = + base_val.exp_u64(reverse_bits_len(exp_val as usize, exp_bits.len()) as u64); + self.memory.mw(result, Block::from(out), mult); + self.record.exp_reverse_bits_len_events.push(ExpReverseBitsEvent { + result: out, + base: base_val, + exp: exp_bits, + }); + } + Instruction::HintBits(HintBitsInstr { output_addrs_mults, input_addr }) => { + self.nb_bit_decompositions += 1; + let num = self.memory.mr_mult(input_addr, F::zero()).val[0].as_canonical_u32(); + // Decompose the num into LE bits. + let bits = (0..output_addrs_mults.len()) + .map(|i| Block::from(F::from_canonical_u32((num >> i) & 1))) + .collect::>(); + // Write the bits to the array at dst. + for (bit, (addr, mult)) in bits.into_iter().zip(output_addrs_mults) { + self.memory.mw(addr, bit, mult); + self.record.mem_var_events.push(MemEvent { inner: bit }); + } + } + + Instruction::FriFold(instr) => { + let FriFoldInstr { + base_single_addrs, + ext_single_addrs, + ext_vec_addrs, + alpha_pow_mults, + ro_mults, + } = *instr; + self.nb_fri_fold += 1; + let x = self.memory.mr(base_single_addrs.x).val[0]; + let z = self.memory.mr(ext_single_addrs.z).val; + let z: EF = z.ext(); + let alpha = self.memory.mr(ext_single_addrs.alpha).val; + let alpha: EF = alpha.ext(); + let mat_opening = ext_vec_addrs + .mat_opening + .iter() + .map(|addr| self.memory.mr(*addr).val) + .collect_vec(); + let ps_at_z = ext_vec_addrs + .ps_at_z + .iter() + .map(|addr| self.memory.mr(*addr).val) + .collect_vec(); + + for m in 0..ps_at_z.len() { + // let m = F::from_canonical_u32(m); + // Get the opening values. + let p_at_x = mat_opening[m]; + let p_at_x: EF = p_at_x.ext(); + let p_at_z = ps_at_z[m]; + let p_at_z: EF = p_at_z.ext(); + + // Calculate the quotient and update the values + let quotient = (-p_at_z + p_at_x) / (-z + x); + + // First we peek to get the current value. + let alpha_pow: EF = + self.memory.mr(ext_vec_addrs.alpha_pow_input[m]).val.ext(); + + let ro: EF = self.memory.mr(ext_vec_addrs.ro_input[m]).val.ext(); + + let new_ro = ro + alpha_pow * quotient; + let new_alpha_pow = alpha_pow * alpha; + + let _ = self.memory.mw( + ext_vec_addrs.ro_output[m], + Block::from(new_ro.as_base_slice()), + ro_mults[m], + ); + + let _ = self.memory.mw( + ext_vec_addrs.alpha_pow_output[m], + Block::from(new_alpha_pow.as_base_slice()), + alpha_pow_mults[m], + ); + + self.record.fri_fold_events.push(FriFoldEvent { + base_single: FriFoldBaseIo { x }, + ext_single: FriFoldExtSingleIo { + z: Block::from(z.as_base_slice()), + alpha: Block::from(alpha.as_base_slice()), + }, + ext_vec: FriFoldExtVecIo { + mat_opening: Block::from(p_at_x.as_base_slice()), + ps_at_z: Block::from(p_at_z.as_base_slice()), + alpha_pow_input: Block::from(alpha_pow.as_base_slice()), + ro_input: Block::from(ro.as_base_slice()), + alpha_pow_output: Block::from(new_alpha_pow.as_base_slice()), + ro_output: Block::from(new_ro.as_base_slice()), + }, + }); + } + } + + Instruction::CommitPublicValues(instr) => { + let pv_addrs = instr.pv_addrs.to_vec(); + let pv_values: [F; RECURSIVE_PROOF_NUM_PV_ELTS] = + array::from_fn(|i| self.memory.mr(pv_addrs[i]).val[0]); + self.record.public_values = *pv_values.as_slice().borrow(); + self.record + .commit_pv_hash_events + .push(CommitPublicValuesEvent { public_values: self.record.public_values }); + } + + Instruction::Print(PrintInstr { field_elt_type, addr }) => match field_elt_type { + FieldEltType::Base => { + self.nb_print_f += 1; + let f = self.memory.mr_mult(addr, F::zero()).val[0]; + writeln!(self.debug_stdout, "PRINTF={f}") + } + FieldEltType::Extension => { + self.nb_print_e += 1; + let ef = self.memory.mr_mult(addr, F::zero()).val; + writeln!(self.debug_stdout, "PRINTEF={ef:?}") + } + } + .map_err(RuntimeError::DebugPrint)?, + Instruction::HintExt2Felts(HintExt2FeltsInstr { + output_addrs_mults, + input_addr, + }) => { + self.nb_bit_decompositions += 1; + let fs = self.memory.mr_mult(input_addr, F::zero()).val; + // Write the bits to the array at dst. + for (f, (addr, mult)) in fs.into_iter().zip(output_addrs_mults) { + let felt = Block::from(f); + self.memory.mw(addr, felt, mult); + self.record.mem_var_events.push(MemEvent { inner: felt }); + } + } + Instruction::Hint(HintInstr { output_addrs_mults }) => { + // Check that enough Blocks can be read, so `drain` does not panic. + if self.witness_stream.len() < output_addrs_mults.len() { + return Err(RuntimeError::EmptyWitnessStream); + } + let witness = self.witness_stream.drain(0..output_addrs_mults.len()); + for ((addr, mult), val) in zip(output_addrs_mults, witness) { + // Inline [`Self::mw`] to mutably borrow multiple fields of `self`. + self.memory.mw(addr, val, mult); + self.record.mem_var_events.push(MemEvent { inner: val }); + } + } + } + + self.pc = next_pc; + self.clk = next_clk; + self.timestamp += 1; + + if self.timestamp >= early_exit_ts { + break; + } + } + Ok(()) + } +} diff --git a/crates/recursion/core-v2/src/runtime/opcode.rs b/crates/recursion/core-v2/src/runtime/opcode.rs new file mode 100644 index 0000000000..96a748d065 --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/opcode.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum BaseAluOpcode { + AddF, + SubF, + MulF, + DivF, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ExtAluOpcode { + AddE, + SubE, + MulE, + DivE, +} diff --git a/crates/recursion/core-v2/src/runtime/program.rs b/crates/recursion/core-v2/src/runtime/program.rs new file mode 100644 index 0000000000..faa5a6f730 --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/program.rs @@ -0,0 +1,20 @@ +use backtrace::Backtrace; +use p3_field::Field; +use serde::{Deserialize, Serialize}; +use sp1_stark::air::MachineProgram; + +use crate::*; + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct RecursionProgram { + pub instructions: Vec>, + pub total_memory: usize, + #[serde(skip)] + pub traces: Vec>, +} + +impl MachineProgram for RecursionProgram { + fn pc_start(&self) -> F { + F::zero() + } +} diff --git a/crates/recursion/core-v2/src/runtime/record.rs b/crates/recursion/core-v2/src/runtime/record.rs new file mode 100644 index 0000000000..59bb10ad7c --- /dev/null +++ b/crates/recursion/core-v2/src/runtime/record.rs @@ -0,0 +1,74 @@ +use std::{array, sync::Arc}; + +use p3_field::{AbstractField, PrimeField32}; +use sp1_recursion_core::air::RecursionPublicValues; +use sp1_stark::{MachineRecord, SP1CoreOpts, PROOF_MAX_NUM_PVS}; + +// TODO expand glob imports +use crate::*; + +#[derive(Clone, Default, Debug)] +pub struct ExecutionRecord { + pub program: Arc>, + /// The index of the shard. + pub index: u32, + + pub base_alu_events: Vec>, + pub ext_alu_events: Vec>, + pub mem_const_count: usize, + pub mem_var_events: Vec>, + /// The public values. + pub public_values: RecursionPublicValues, + + pub poseidon2_events: Vec>, + pub exp_reverse_bits_len_events: Vec>, + pub fri_fold_events: Vec>, + pub commit_pv_hash_events: Vec>, +} + +impl MachineRecord for ExecutionRecord { + type Config = SP1CoreOpts; + + fn stats(&self) -> hashbrown::HashMap { + hashbrown::HashMap::from([("cpu_events".to_owned(), 1337usize)]) + } + + fn append(&mut self, other: &mut Self) { + // Exhaustive destructuring for refactoring purposes. + let Self { + program: _, + index: _, + base_alu_events, + ext_alu_events, + mem_const_count, + mem_var_events, + public_values: _, + poseidon2_events, + exp_reverse_bits_len_events, + fri_fold_events, + commit_pv_hash_events, + } = self; + base_alu_events.append(&mut other.base_alu_events); + ext_alu_events.append(&mut other.ext_alu_events); + *mem_const_count += other.mem_const_count; + mem_var_events.append(&mut other.mem_var_events); + poseidon2_events.append(&mut other.poseidon2_events); + exp_reverse_bits_len_events.append(&mut other.exp_reverse_bits_len_events); + fri_fold_events.append(&mut other.fri_fold_events); + commit_pv_hash_events.append(&mut other.commit_pv_hash_events); + } + + fn public_values(&self) -> Vec { + let pv_elms = self.public_values.to_vec(); + + let ret: [T; PROOF_MAX_NUM_PVS] = array::from_fn(|i| { + if i < pv_elms.len() { + T::from_canonical_u32(pv_elms[i].as_canonical_u32()) + } else { + T::zero() + } + }); + + ret.to_vec() + } +} diff --git a/recursion/core/CHANGELOG.md b/crates/recursion/core/CHANGELOG.md similarity index 100% rename from recursion/core/CHANGELOG.md rename to crates/recursion/core/CHANGELOG.md diff --git a/recursion/core/Cargo.toml b/crates/recursion/core/Cargo.toml similarity index 89% rename from recursion/core/Cargo.toml rename to crates/recursion/core/Cargo.toml index 95073c58a2..7803c2f52e 100644 --- a/recursion/core/Cargo.toml +++ b/crates/recursion/core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-core" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -21,7 +21,9 @@ p3-symmetric = { workspace = true } sp1-derive = { workspace = true } sp1-primitives = { workspace = true } tracing = "0.1.40" -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } +sp1-stark = { workspace = true } +sp1-core-executor = { workspace = true } hashbrown = { version = "0.14.5", features = ["serde"] } itertools = "0.13.0" p3-bn254-fr = { workspace = true } diff --git a/recursion/core/src/air/block.rs b/crates/recursion/core/src/air/block.rs similarity index 91% rename from recursion/core/src/air/block.rs rename to crates/recursion/core/src/air/block.rs index 5cc89add8c..0619659cc3 100644 --- a/recursion/core/src/air/block.rs +++ b/crates/recursion/core/src/air/block.rs @@ -1,14 +1,10 @@ use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::ExtensionField; -use p3_field::Field; +use p3_field::{AbstractField, ExtensionField, Field}; use serde::{Deserialize, Serialize}; -use sp1_core::air::ExtensionAirBuilder; -use sp1_core::air::{BinomialExtension, SP1AirBuilder}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BinomialExtension, ExtensionAirBuilder, SP1AirBuilder}; -use std::ops::Index; -use std::ops::IndexMut; +use std::ops::{Index, IndexMut}; use crate::runtime::D; diff --git a/recursion/core/src/air/builder.rs b/crates/recursion/core/src/air/builder.rs similarity index 87% rename from recursion/core/src/air/builder.rs rename to crates/recursion/core/src/air/builder.rs index e2ea45e4f2..0794f09bd9 100644 --- a/recursion/core/src/air/builder.rs +++ b/crates/recursion/core/src/air/builder.rs @@ -1,12 +1,14 @@ -use crate::cpu::{InstructionCols, OpcodeSelectorCols}; -use crate::memory::{MemoryAccessTimestampCols, MemoryCols}; -use crate::range_check::RangeCheckOpcode; +use crate::{ + cpu::{InstructionCols, OpcodeSelectorCols}, + memory::{MemoryAccessTimestampCols, MemoryCols}, + range_check::RangeCheckOpcode, +}; use core::iter::{once, repeat}; use p3_air::{AirBuilder, AirBuilderWithPublicValues}; use p3_field::AbstractField; -use sp1_core::{ +use sp1_stark::{ air::{AirInteraction, BaseAirBuilder, MachineAirBuilder}, - lookup::InteractionKind, + InteractionKind, }; use super::Block; @@ -48,16 +50,8 @@ pub trait RecursionMemoryAirBuilder: RecursionInteractionAirBuilder { .chain(memory_access.value().clone().map(Into::into)) .collect(); - self.receive(AirInteraction::new( - prev_values, - is_real.clone(), - InteractionKind::Memory, - )); - self.send(AirInteraction::new( - current_values, - is_real, - InteractionKind::Memory, - )); + self.receive(AirInteraction::new(prev_values, is_real.clone(), InteractionKind::Memory)); + self.send(AirInteraction::new(current_values, is_real, InteractionKind::Memory)); } fn recursion_eval_memory_access_single + Clone>( @@ -88,16 +82,8 @@ pub trait RecursionMemoryAirBuilder: RecursionInteractionAirBuilder { .chain(repeat(Self::Expr::zero()).take(3)) .collect(); - self.receive(AirInteraction::new( - prev_values, - is_real.clone(), - InteractionKind::Memory, - )); - self.send(AirInteraction::new( - current_values, - is_real, - InteractionKind::Memory, - )); + self.receive(AirInteraction::new(prev_values, is_real.clone(), InteractionKind::Memory)); + self.send(AirInteraction::new(current_values, is_real, InteractionKind::Memory)); } /// Verifies that the memory access happens after the previous memory access. @@ -125,8 +111,8 @@ pub trait RecursionMemoryAirBuilder: RecursionInteractionAirBuilder { /// /// This method verifies that the inputted is less than 2^24 by doing a 16 bit and 12 bit range /// check on it's limbs. It will also verify that the limbs are correct. This method is needed - /// since the memory access timestamp check (see [Self::eval_memory_access_timestamp]) needs to assume - /// the clk is within 28 bits. + /// since the memory access timestamp check (see [Self::eval_memory_access_timestamp]) needs to + /// assume the clk is within 28 bits. fn eval_range_check_28bits( &mut self, value: impl Into, @@ -230,11 +216,7 @@ pub trait RecursionInteractionAirBuilder: BaseAirBuilder { ) { let table_interaction_vals = table.iter().map(|x| x.clone().into()); let values = once(opcode.into()).chain(table_interaction_vals).collect(); - self.send(AirInteraction::new( - values, - is_real.into(), - InteractionKind::Syscall, - )); + self.send(AirInteraction::new(values, is_real.into(), InteractionKind::Syscall)); } fn receive_table + Clone>( @@ -245,10 +227,6 @@ pub trait RecursionInteractionAirBuilder: BaseAirBuilder { ) { let table_interaction_vals = table.iter().map(|x| x.clone().into()); let values = once(opcode.into()).chain(table_interaction_vals).collect(); - self.receive(AirInteraction::new( - values, - is_real.into(), - InteractionKind::Syscall, - )); + self.receive(AirInteraction::new(values, is_real.into(), InteractionKind::Syscall)); } } diff --git a/recursion/core/src/air/extension.rs b/crates/recursion/core/src/air/extension.rs similarity index 81% rename from recursion/core/src/air/extension.rs rename to crates/recursion/core/src/air/extension.rs index 179dca3b69..fbe547345f 100644 --- a/recursion/core/src/air/extension.rs +++ b/crates/recursion/core/src/air/extension.rs @@ -1,6 +1,8 @@ -use p3_field::extension::{BinomialExtensionField, BinomiallyExtendable}; -use p3_field::{AbstractExtensionField, Field}; -use sp1_core::air::BinomialExtension; +use p3_field::{ + extension::{BinomialExtensionField, BinomiallyExtendable}, + AbstractExtensionField, Field, +}; +use sp1_stark::air::BinomialExtension; use super::Block; diff --git a/recursion/core/src/air/is_ext_zero.rs b/crates/recursion/core/src/air/is_ext_zero.rs similarity index 89% rename from recursion/core/src/air/is_ext_zero.rs rename to crates/recursion/core/src/air/is_ext_zero.rs index 6ccc332253..39a251cda8 100644 --- a/recursion/core/src/air/is_ext_zero.rs +++ b/crates/recursion/core/src/air/is_ext_zero.rs @@ -6,15 +6,14 @@ //! is 0. use crate::air::Block; use p3_air::AirBuilder; -use p3_field::extension::BinomialExtensionField; -use p3_field::extension::BinomiallyExtendable; -use p3_field::AbstractField; -use p3_field::Field; -use sp1_core::air::BinomialExtension; +use p3_field::{ + extension::{BinomialExtensionField, BinomiallyExtendable}, + AbstractField, Field, +}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BinomialExtension, SP1AirBuilder}; use crate::air::extension::BinomialExtensionUtils; -use sp1_core::air::SP1AirBuilder; use crate::runtime::D; @@ -86,10 +85,7 @@ impl IsExtZeroOperation { // If the result is 1, then the input is 0. for x in a { - builder - .when(is_real.clone()) - .when(cols.result) - .assert_zero(x.clone()); + builder.when(is_real.clone()).when(cols.result).assert_zero(x.clone()); } } } diff --git a/recursion/core/src/air/is_zero.rs b/crates/recursion/core/src/air/is_zero.rs similarity index 82% rename from recursion/core/src/air/is_zero.rs rename to crates/recursion/core/src/air/is_zero.rs index 6e92ef5dd1..c1e469c490 100644 --- a/recursion/core/src/air/is_zero.rs +++ b/crates/recursion/core/src/air/is_zero.rs @@ -5,11 +5,9 @@ //! The idea is that 1 - input * inverse is exactly the boolean value indicating whether the input //! is 0. use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use sp1_derive::AlignedBorrow; - -use sp1_core::air::SP1AirBuilder; +use sp1_stark::air::SP1AirBuilder; /// A set of columns needed to compute whether the given word is 0. #[derive(AlignedBorrow, Default, Debug, Clone, Copy)] @@ -24,11 +22,8 @@ pub struct IsZeroOperation { impl IsZeroOperation { pub fn populate(&mut self, a: F) -> F { - let (inverse, result) = if a.is_zero() { - (F::zero(), F::one()) - } else { - (a.inverse(), F::zero()) - }; + let (inverse, result) = + if a.is_zero() { (F::zero(), F::one()) } else { (a.inverse(), F::zero()) }; self.inverse = inverse; self.result = result; @@ -68,16 +63,11 @@ impl IsZeroOperation { let is_zero = one.clone() - inverse * a.clone(); - builder - .when(is_real.clone()) - .assert_eq(is_zero, cols.result); + builder.when(is_real.clone()).assert_eq(is_zero, cols.result); builder.when(is_real.clone()).assert_bool(cols.result); // If the result is 1, then the input is 0. - builder - .when(is_real.clone()) - .when(cols.result) - .assert_zero(a.clone()); + builder.when(is_real.clone()).when(cols.result).assert_zero(a.clone()); } } diff --git a/recursion/core/src/air/mod.rs b/crates/recursion/core/src/air/mod.rs similarity index 100% rename from recursion/core/src/air/mod.rs rename to crates/recursion/core/src/air/mod.rs diff --git a/recursion/core/src/air/multi_builder.rs b/crates/recursion/core/src/air/multi_builder.rs similarity index 91% rename from recursion/core/src/air/multi_builder.rs rename to crates/recursion/core/src/air/multi_builder.rs index 63ad786084..48711b5294 100644 --- a/recursion/core/src/air/multi_builder.rs +++ b/crates/recursion/core/src/air/multi_builder.rs @@ -2,15 +2,15 @@ use p3_air::{ AirBuilder, AirBuilderWithPublicValues, ExtensionBuilder, FilteredAirBuilder, PermutationAirBuilder, }; -use sp1_core::air::MessageBuilder; +use sp1_stark::air::MessageBuilder; /// The MultiBuilder is used for the multi table. It is used to create a virtual builder for one of /// the sub tables in the multi table. pub struct MultiBuilder<'a, AB: AirBuilder> { inner: FilteredAirBuilder<'a, AB>, - /// These fields are used to determine whether a row is is the first or last row of the subtable, - /// which requires hinting from the parent table. + /// These fields are used to determine whether a row is is the first or last row of the + /// subtable, which requires hinting from the parent table. is_first_row: AB::Expr, is_last_row: AB::Expr, @@ -26,12 +26,7 @@ impl<'a, AB: AirBuilder> MultiBuilder<'a, AB> { next_condition: AB::Expr, ) -> Self { let inner = builder.when(local_condition.clone()); - Self { - inner, - is_first_row, - is_last_row, - next_condition, - } + Self { inner, is_first_row, is_last_row, next_condition } } } diff --git a/recursion/core/src/air/public_values.rs b/crates/recursion/core/src/air/public_values.rs similarity index 88% rename from recursion/core/src/air/public_values.rs rename to crates/recursion/core/src/air/public_values.rs index 4c9708e138..3a30efc84f 100644 --- a/recursion/core/src/air/public_values.rs +++ b/crates/recursion/core/src/air/public_values.rs @@ -5,14 +5,14 @@ use p3_challenger::DuplexChallenger; use p3_field::PrimeField32; use p3_symmetric::CryptographicPermutation; use serde::{Deserialize, Serialize}; -use sp1_core::{ - air::{Word, POSEIDON_NUM_WORDS}, - stark::PROOF_MAX_NUM_PVS, - utils::indices_arr, -}; +use sp1_core_machine::utils::indices_arr; use sp1_derive::AlignedBorrow; +use sp1_stark::{air::POSEIDON_NUM_WORDS, Word, PROOF_MAX_NUM_PVS}; use static_assertions::const_assert_eq; -use std::mem::{size_of, transmute}; +use std::{ + borrow::BorrowMut, + mem::{size_of, transmute}, +}; pub const PV_DIGEST_NUM_WORDS: usize = 8; @@ -131,7 +131,18 @@ pub struct RecursionPublicValues { /// The digest of all the previous public values elements. pub digest: [T; DIGEST_SIZE], - /// The exit code of the program. Note that this is not part of the public values digest, since - /// it's value will be individually constrained. + /// The exit code of the program. Note that this is not part of the public values digest, + /// since it's value will be individually constrained. pub exit_code: T, } + +/// Converts the public values to an array of elements. +impl RecursionPublicValues { + pub fn to_vec(&self) -> [F; RECURSIVE_PROOF_NUM_PV_ELTS] { + let mut ret = [F::default(); RECURSIVE_PROOF_NUM_PV_ELTS]; + let pv: &mut RecursionPublicValues = ret.as_mut_slice().borrow_mut(); + + *pv = *self; + ret + } +} diff --git a/recursion/core/src/cpu/air/alu.rs b/crates/recursion/core/src/cpu/air/alu.rs similarity index 92% rename from recursion/core/src/cpu/air/alu.rs rename to crates/recursion/core/src/cpu/air/alu.rs index 761617a90c..54e11305ed 100644 --- a/recursion/core/src/cpu/air/alu.rs +++ b/crates/recursion/core/src/cpu/air/alu.rs @@ -1,6 +1,6 @@ use p3_air::AirBuilder; use p3_field::{AbstractField, Field}; -use sp1_core::air::{BinomialExtension, ExtensionAirBuilder}; +use sp1_stark::air::{BinomialExtension, ExtensionAirBuilder}; use crate::{ air::{BinomialExtensionUtils, SP1RecursionAirBuilder}, @@ -49,8 +49,6 @@ impl CpuChip { .when(local.selectors.is_mul) .assert_ext_eq(a_ext.clone(), b_ext.clone() * c_ext.clone()); // For div operation, we assert that b == a * c (equivalent to a == b / c). - builder - .when(local.selectors.is_div) - .assert_ext_eq(b_ext, a_ext * c_ext); + builder.when(local.selectors.is_div).assert_ext_eq(b_ext, a_ext * c_ext); } } diff --git a/recursion/core/src/cpu/air/branch.rs b/crates/recursion/core/src/cpu/air/branch.rs similarity index 94% rename from recursion/core/src/cpu/air/branch.rs rename to crates/recursion/core/src/cpu/air/branch.rs index 105dd771da..2bccb417d6 100644 --- a/recursion/core/src/cpu/air/branch.rs +++ b/crates/recursion/core/src/cpu/air/branch.rs @@ -1,6 +1,6 @@ use p3_air::AirBuilder; use p3_field::{AbstractField, Field}; -use sp1_core::air::{BinomialExtension, ExtensionAirBuilder}; +use sp1_stark::air::{BinomialExtension, ExtensionAirBuilder}; use crate::{ air::{ @@ -63,9 +63,7 @@ impl CpuChip { let mut do_branch = local.selectors.is_beq * branch_cols.comparison_diff.result; do_branch += local.selectors.is_bne * (one.clone() - branch_cols.comparison_diff.result); do_branch += local.selectors.is_bneinc * (one.clone() - branch_cols.comparison_diff.result); - builder - .when(is_branch_instruction.clone()) - .assert_eq(branch_cols.do_branch, do_branch); + builder.when(is_branch_instruction.clone()).assert_eq(branch_cols.do_branch, do_branch); // Verify branch_col.next_pc col. let pc_offset = local.c.value().0[0]; diff --git a/recursion/core/src/cpu/air/heap.rs b/crates/recursion/core/src/cpu/air/heap.rs similarity index 100% rename from recursion/core/src/cpu/air/heap.rs rename to crates/recursion/core/src/cpu/air/heap.rs diff --git a/recursion/core/src/cpu/air/jump.rs b/crates/recursion/core/src/cpu/air/jump.rs similarity index 79% rename from recursion/core/src/cpu/air/jump.rs rename to crates/recursion/core/src/cpu/air/jump.rs index dd5e9b8bba..8dbd002c02 100644 --- a/recursion/core/src/cpu/air/jump.rs +++ b/crates/recursion/core/src/cpu/air/jump.rs @@ -24,25 +24,18 @@ impl CpuChip { let is_jump_instr = self.is_jump_instruction::(local); // Verify the next row's fp. - builder - .when_first_row() - .assert_eq(local.fp, F::from_canonical_usize(STACK_SIZE)); + builder.when_first_row().assert_eq(local.fp, F::from_canonical_usize(STACK_SIZE)); let not_jump_instruction = AB::Expr::one() - is_jump_instr.clone(); let expected_next_fp = local.selectors.is_jal * (local.fp + local.c.value()[0]) + local.selectors.is_jalr * local.c.value()[0] + not_jump_instruction * local.fp; - builder - .when_transition() - .when(next.is_real) - .assert_eq(next.fp, expected_next_fp); + builder.when_transition().when(next.is_real).assert_eq(next.fp, expected_next_fp); // Verify the a operand values. let expected_a_val = local.selectors.is_jal * local.pc + local.selectors.is_jalr * (local.pc + AB::Expr::one()); let expected_a_val_block = Block::from(expected_a_val); - builder - .when(is_jump_instr) - .assert_block_eq(*local.a.value(), expected_a_val_block); + builder.when(is_jump_instr).assert_block_eq(*local.a.value(), expected_a_val_block); // Add to the `next_pc` expression. *next_pc += local.selectors.is_jal * (local.pc + local.b.value()[0]); diff --git a/recursion/core/src/cpu/air/memory.rs b/crates/recursion/core/src/cpu/air/memory.rs similarity index 79% rename from recursion/core/src/cpu/air/memory.rs rename to crates/recursion/core/src/cpu/air/memory.rs index d1b024130f..9ba2912958 100644 --- a/recursion/core/src/cpu/air/memory.rs +++ b/crates/recursion/core/src/cpu/air/memory.rs @@ -1,6 +1,6 @@ use p3_air::AirBuilder; use p3_field::Field; -use sp1_core::runtime::MemoryAccessPosition; +use sp1_core_executor::events::MemoryAccessPosition; use crate::{ air::{BlockBuilder, SP1RecursionAirBuilder}, @@ -22,9 +22,7 @@ impl CpuChip { let memory_cols = local.opcode_specific.memory(); // Check that the memory_cols.memory_addr column equals the computed memory_addr. - builder - .when(is_memory_instr.clone()) - .assert_eq(memory_addr, memory_cols.memory_addr); + builder.when(is_memory_instr.clone()).assert_eq(memory_addr, memory_cols.memory_addr); builder.recursion_eval_memory_access( local.clk + AB::F::from_canonical_u32(MemoryAccessPosition::Memory as u32), @@ -35,11 +33,11 @@ impl CpuChip { // Constraints on the memory column depending on load or store. // We read from memory when it is a load. - builder.when(local.selectors.is_load).assert_block_eq( - *memory_cols.memory.prev_value(), - *memory_cols.memory.value(), - ); - // When there is a store, we ensure that we are writing the value of the a operand to the memory. + builder + .when(local.selectors.is_load) + .assert_block_eq(*memory_cols.memory.prev_value(), *memory_cols.memory.value()); + // When there is a store, we ensure that we are writing the value of the a operand to the + // memory. builder .when(is_memory_instr) .assert_block_eq(*local.a.value(), *memory_cols.memory.value()); diff --git a/recursion/core/src/cpu/air/mod.rs b/crates/recursion/core/src/cpu/air/mod.rs similarity index 86% rename from recursion/core/src/cpu/air/mod.rs rename to crates/recursion/core/src/cpu/air/mod.rs index 2dfcb9a1d4..437696a0ca 100644 --- a/recursion/core/src/cpu/air/mod.rs +++ b/crates/recursion/core/src/cpu/air/mod.rs @@ -12,7 +12,7 @@ use std::borrow::Borrow; use p3_air::{Air, AirBuilder}; use p3_field::{AbstractField, Field}; use p3_matrix::Matrix; -use sp1_core::air::BaseAirBuilder; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::{RecursionPublicValues, SP1RecursionAirBuilder, RECURSIVE_PROOF_NUM_PV_ELTS}, @@ -40,15 +40,9 @@ where // Constrain the program. // Constraints for "fake" columns. - builder - .when_not(local.is_real) - .assert_one(local.instruction.imm_b); - builder - .when_not(local.is_real) - .assert_one(local.instruction.imm_c); - builder - .when_not(local.is_real) - .assert_one(local.selectors.is_noop); + builder.when_not(local.is_real).assert_one(local.instruction.imm_b); + builder.when_not(local.is_real).assert_one(local.instruction.imm_c); + builder.when_not(local.is_real).assert_one(local.selectors.is_noop); local .selectors @@ -74,8 +68,8 @@ where // Constrain branches and jumps and constrain the next pc. { - // Expression for the expected next_pc. This will be added to in `eval_branch` and `eval_jump` - // to account for possible jumps and branches. + // Expression for the expected next_pc. This will be added to in `eval_branch` and + // `eval_jump` to account for possible jumps and branches. let mut next_pc = zero; self.eval_branch(builder, local, &mut next_pc); @@ -88,10 +82,7 @@ where - self.is_jump_instruction::(local); next_pc += not_branch_or_jump.clone() * (local.pc + one); - builder - .when_transition() - .when(next.is_real) - .assert_eq(next_pc, next.pc); + builder.when_transition().when(next.is_real).assert_eq(next_pc, next.pc); } // Constrain the syscalls. @@ -175,10 +166,7 @@ impl CpuChip { builder.when_first_row().assert_one(local.is_real); // Once rows transition to not real, then they should stay not real. - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when_not(local.is_real).assert_zero(next.is_real); } /// Expr to check for alu instructions. @@ -254,32 +242,24 @@ impl CpuChip { #[cfg(test)] mod tests { use itertools::Itertools; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use std::time::Instant; - use p3_baby_bear::BabyBear; - use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_field::AbstractField; use p3_matrix::{dense::RowMajorMatrix, Matrix}; - use p3_poseidon2::Poseidon2; - use p3_poseidon2::Poseidon2ExternalMatrixGeneral; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::{ - air::MachineAir, - utils::{uni_stark_prove, uni_stark_verify, BabyBearPoseidon2}, - }; - - use crate::air::Block; - use crate::memory::MemoryGlobalChip; - use crate::runtime::ExecutionRecord; + use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use sp1_core_machine::utils::{uni_stark_prove, uni_stark_verify}; + use sp1_stark::air::MachineAir; + + use crate::{air::Block, memory::MemoryGlobalChip, runtime::ExecutionRecord}; #[test] fn test_cpu_unistark() { let config = BabyBearPoseidon2::compressed(); let mut challenger = config.challenger(); - let chip = MemoryGlobalChip { - fixed_log2_rows: None, - }; + let chip = MemoryGlobalChip { fixed_log2_rows: None }; let test_vals = (0..16).map(BabyBear::from_canonical_u32).collect_vec(); @@ -290,18 +270,12 @@ mod tests { } // Add a dummy initialize event because the AIR expects at least one. - input_exec - .first_memory_record - .push((BabyBear::zero(), Block::from(BabyBear::zero()))); + input_exec.first_memory_record.push((BabyBear::zero(), Block::from(BabyBear::zero()))); println!("input exec: {:?}", input_exec.last_memory_record.len()); let trace: RowMajorMatrix = chip.generate_trace(&input_exec, &mut ExecutionRecord::::default()); - println!( - "trace dims is width: {:?}, height: {:?}", - trace.width(), - trace.height() - ); + println!("trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); let start = Instant::now(); let proof = uni_stark_prove(&config, &chip, &mut challenger, trace); diff --git a/recursion/core/src/cpu/air/operands.rs b/crates/recursion/core/src/cpu/air/operands.rs similarity index 89% rename from recursion/core/src/cpu/air/operands.rs rename to crates/recursion/core/src/cpu/air/operands.rs index e67cea6dd1..68f0391d7c 100644 --- a/recursion/core/src/cpu/air/operands.rs +++ b/crates/recursion/core/src/cpu/air/operands.rs @@ -1,5 +1,5 @@ use p3_field::{AbstractField, Field}; -use sp1_core::runtime::MemoryAccessPosition; +use sp1_core_executor::events::MemoryAccessPosition; use crate::{ air::{BlockBuilder, SP1RecursionAirBuilder}, @@ -29,11 +29,10 @@ impl CpuChip { &local.a, local.is_real.into(), ); - // If the instruction only reads from operand A, then verify that previous and current values are equal. + // If the instruction only reads from operand A, then verify that previous and current + // values are equal. let is_op_a_read_only = self.is_op_a_read_only_instruction::(local); - builder - .when(is_op_a_read_only) - .assert_block_eq(*local.a.prev_value(), *local.a.value()); + builder.when(is_op_a_read_only).assert_block_eq(*local.a.prev_value(), *local.a.value()); builder.recursion_eval_memory_access( local.clk + AB::F::from_canonical_u32(MemoryAccessPosition::B as u32), diff --git a/recursion/core/src/cpu/air/public_values.rs b/crates/recursion/core/src/cpu/air/public_values.rs similarity index 78% rename from recursion/core/src/cpu/air/public_values.rs rename to crates/recursion/core/src/cpu/air/public_values.rs index 15a23828f9..533c17b4fc 100644 --- a/recursion/core/src/cpu/air/public_values.rs +++ b/crates/recursion/core/src/cpu/air/public_values.rs @@ -26,24 +26,18 @@ impl CpuChip { // Verify all elements in the index bitmap are bools. let mut bitmap_sum = AB::Expr::zero(); for bit in public_values_cols.idx_bitmap.iter() { - builder - .when(is_commit_instruction.clone()) - .assert_bool(*bit); + builder.when(is_commit_instruction.clone()).assert_bool(*bit); bitmap_sum += (*bit).into(); } // When the instruction is COMMIT there should be exactly one set bit. - builder - .when(is_commit_instruction.clone()) - .assert_one(bitmap_sum.clone()); + builder.when(is_commit_instruction.clone()).assert_one(bitmap_sum.clone()); // Verify that idx passed in the b operand corresponds to the set bit in index bitmap. for (i, bit) in public_values_cols.idx_bitmap.iter().enumerate() { - builder - .when(*bit * is_commit_instruction.clone()) - .assert_block_eq( - *local.b.prev_value(), - AB::Expr::from_canonical_u32(i as u32).into(), - ); + builder.when(*bit * is_commit_instruction.clone()).assert_block_eq( + *local.b.prev_value(), + AB::Expr::from_canonical_u32(i as u32).into(), + ); } // Calculated the expected public value. diff --git a/recursion/core/src/cpu/air/system.rs b/crates/recursion/core/src/cpu/air/system.rs similarity index 73% rename from recursion/core/src/cpu/air/system.rs rename to crates/recursion/core/src/cpu/air/system.rs index db20bf201e..9c5420b99e 100644 --- a/recursion/core/src/cpu/air/system.rs +++ b/crates/recursion/core/src/cpu/air/system.rs @@ -1,6 +1,6 @@ use p3_air::AirBuilder; use p3_field::Field; -use sp1_core::air::BaseAirBuilder; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::{RecursionPublicValues, SP1RecursionAirBuilder}, @@ -27,10 +27,7 @@ impl CpuChip { .when_not(next.is_real) .assert_one(is_system_instruction.clone()); - builder - .when_last_row() - .when(local.is_real) - .assert_one(is_system_instruction.clone()); + builder.when_last_row().when(local.is_real).assert_one(is_system_instruction.clone()); // Verify that all other real rows are not TRAP or HALT. builder @@ -40,12 +37,8 @@ impl CpuChip { .assert_zero(is_system_instruction); // Verify the correct public value exit code. - builder - .when(local.selectors.is_trap) - .assert_one(public_values.exit_code.clone()); + builder.when(local.selectors.is_trap).assert_one(public_values.exit_code.clone()); - builder - .when(local.selectors.is_halt) - .assert_zero(public_values.exit_code.clone()); + builder.when(local.selectors.is_halt).assert_zero(public_values.exit_code.clone()); } } diff --git a/recursion/core/src/cpu/columns/branch.rs b/crates/recursion/core/src/cpu/columns/branch.rs similarity index 91% rename from recursion/core/src/cpu/columns/branch.rs rename to crates/recursion/core/src/cpu/columns/branch.rs index 48efaa07bd..58e33081fd 100644 --- a/recursion/core/src/cpu/columns/branch.rs +++ b/crates/recursion/core/src/cpu/columns/branch.rs @@ -1,5 +1,5 @@ -use sp1_core::air::BinomialExtension; use sp1_derive::AlignedBorrow; +use sp1_stark::air::BinomialExtension; use std::mem::size_of; use crate::air::IsExtZeroOperation; diff --git a/recursion/core/src/cpu/columns/heap_expand.rs b/crates/recursion/core/src/cpu/columns/heap_expand.rs similarity index 100% rename from recursion/core/src/cpu/columns/heap_expand.rs rename to crates/recursion/core/src/cpu/columns/heap_expand.rs diff --git a/recursion/core/src/cpu/columns/instruction.rs b/crates/recursion/core/src/cpu/columns/instruction.rs similarity index 100% rename from recursion/core/src/cpu/columns/instruction.rs rename to crates/recursion/core/src/cpu/columns/instruction.rs diff --git a/recursion/core/src/cpu/columns/memory.rs b/crates/recursion/core/src/cpu/columns/memory.rs similarity index 100% rename from recursion/core/src/cpu/columns/memory.rs rename to crates/recursion/core/src/cpu/columns/memory.rs diff --git a/recursion/core/src/cpu/columns/mod.rs b/crates/recursion/core/src/cpu/columns/mod.rs similarity index 100% rename from recursion/core/src/cpu/columns/mod.rs rename to crates/recursion/core/src/cpu/columns/mod.rs diff --git a/recursion/core/src/cpu/columns/opcode.rs b/crates/recursion/core/src/cpu/columns/opcode.rs similarity index 96% rename from recursion/core/src/cpu/columns/opcode.rs rename to crates/recursion/core/src/cpu/columns/opcode.rs index a3d85a93b4..9bc733b83e 100644 --- a/recursion/core/src/cpu/columns/opcode.rs +++ b/crates/recursion/core/src/cpu/columns/opcode.rs @@ -99,10 +99,7 @@ impl OpcodeSelectorCols { Opcode::HintLen | Opcode::LessThanF => {} } - if matches!( - instruction.opcode, - Opcode::EADD | Opcode::ESUB | Opcode::EMUL | Opcode::EDIV - ) { + if matches!(instruction.opcode, Opcode::EADD | Opcode::ESUB | Opcode::EMUL | Opcode::EDIV) { self.is_ext = F::one(); } diff --git a/recursion/core/src/cpu/columns/opcode_specific.rs b/crates/recursion/core/src/cpu/columns/opcode_specific.rs similarity index 86% rename from recursion/core/src/cpu/columns/opcode_specific.rs rename to crates/recursion/core/src/cpu/columns/opcode_specific.rs index cea91801c1..0e71e41fad 100644 --- a/recursion/core/src/cpu/columns/opcode_specific.rs +++ b/crates/recursion/core/src/cpu/columns/opcode_specific.rs @@ -1,12 +1,14 @@ -use std::fmt::{Debug, Formatter}; -use std::mem::{size_of, transmute}; +use std::{ + fmt::{Debug, Formatter}, + mem::{size_of, transmute}, +}; use static_assertions::const_assert; -use super::branch::BranchCols; -use super::heap_expand::HeapExpandCols; -use super::memory::MemoryCols; -use super::public_values::PublicValuesCols; +use super::{ + branch::BranchCols, heap_expand::HeapExpandCols, memory::MemoryCols, + public_values::PublicValuesCols, +}; pub const NUM_OPCODE_SPECIFIC_COLS: usize = size_of::>(); @@ -25,9 +27,7 @@ impl Default for OpcodeSpecificCols { // We must use the largest field to avoid uninitialized padding bytes. const_assert!(size_of::>() == size_of::>()); - OpcodeSpecificCols { - memory: MemoryCols::::default(), - } + OpcodeSpecificCols { memory: MemoryCols::::default() } } } diff --git a/recursion/core/src/cpu/columns/public_values.rs b/crates/recursion/core/src/cpu/columns/public_values.rs similarity index 100% rename from recursion/core/src/cpu/columns/public_values.rs rename to crates/recursion/core/src/cpu/columns/public_values.rs diff --git a/recursion/core/src/cpu/mod.rs b/crates/recursion/core/src/cpu/mod.rs similarity index 100% rename from recursion/core/src/cpu/mod.rs rename to crates/recursion/core/src/cpu/mod.rs diff --git a/recursion/core/src/cpu/trace.rs b/crates/recursion/core/src/cpu/trace.rs similarity index 88% rename from recursion/core/src/cpu/trace.rs rename to crates/recursion/core/src/cpu/trace.rs index 2f47687a17..fe209115ef 100644 --- a/recursion/core/src/cpu/trace.rs +++ b/crates/recursion/core/src/cpu/trace.rs @@ -10,13 +10,9 @@ use crate::{ }; use p3_field::{extension::BinomiallyExtendable, PrimeField32}; use p3_matrix::dense::RowMajorMatrix; -use p3_maybe_rayon::prelude::IndexedParallelIterator; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSliceMut; -use sp1_core::{ - air::{BinomialExtension, MachineAir}, - utils::{next_power_of_two, par_for_each_row}, -}; +use p3_maybe_rayon::prelude::{IndexedParallelIterator, ParallelIterator, ParallelSliceMut}; +use sp1_core_machine::utils::{next_power_of_two, par_for_each_row}; +use sp1_stark::air::{BinomialExtension, MachineAir}; use tracing::instrument; use super::{CpuChip, CpuCols, NUM_CPU_COLS}; @@ -89,10 +85,7 @@ impl, const L: usize> MachineAir fo } // Populate the branch columns. - if matches!( - event.instruction.opcode, - Opcode::BEQ | Opcode::BNE | Opcode::BNEINC - ) { + if matches!(event.instruction.opcode, Opcode::BEQ | Opcode::BNE | Opcode::BNEINC) { let branch_cols = cols.opcode_specific.branch_mut(); let a_ext: BinomialExtension = BinomialExtensionUtils::from_block(*cols.a.value()); @@ -105,9 +98,7 @@ impl, const L: usize> MachineAir fo _ => unreachable!(), }; - branch_cols - .comparison_diff - .populate((comparison_diff).as_block()); + branch_cols.comparison_diff.populate((comparison_diff).as_block()); branch_cols.comparison_diff_val = comparison_diff; branch_cols.do_branch = F::from_bool(do_branch); branch_cols.next_pc = if do_branch { @@ -130,11 +121,8 @@ impl, const L: usize> MachineAir fo let mut trace = RowMajorMatrix::new(values, NUM_CPU_COLS); // Fill in the dummy values for the padding rows. - let padded_rows = trace - .values - .par_chunks_mut(NUM_CPU_COLS) - .enumerate() - .skip(input.cpu_events.len()); + let padded_rows = + trace.values.par_chunks_mut(NUM_CPU_COLS).enumerate().skip(input.cpu_events.len()); padded_rows.for_each(|(i, row)| { let cols: &mut CpuCols = row.borrow_mut(); cols.selectors.is_noop = F::one(); diff --git a/recursion/core/src/exp_reverse_bits/mod.rs b/crates/recursion/core/src/exp_reverse_bits/mod.rs similarity index 82% rename from recursion/core/src/exp_reverse_bits/mod.rs rename to crates/recursion/core/src/exp_reverse_bits/mod.rs index 5bba68f6f5..06c9de7d98 100644 --- a/recursion/core/src/exp_reverse_bits/mod.rs +++ b/crates/recursion/core/src/exp_reverse_bits/mod.rs @@ -1,24 +1,26 @@ #![allow(clippy::needless_range_loop)] -use crate::air::{Block, IsZeroOperation, RecursionMemoryAirBuilder}; -use crate::memory::{MemoryReadSingleCols, MemoryReadWriteSingleCols}; -use crate::runtime::Opcode; +use crate::{ + air::{Block, IsZeroOperation, RecursionMemoryAirBuilder}, + memory::{MemoryReadSingleCols, MemoryReadWriteSingleCols}, + runtime::Opcode, +}; use core::borrow::Borrow; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_util::reverse_bits_len; -use sp1_core::air::{BaseAirBuilder, ExtensionAirBuilder, MachineAir, SP1AirBuilder}; -use sp1_core::utils::{next_power_of_two, par_for_each_row}; +use sp1_core_machine::utils::{next_power_of_two, par_for_each_row}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, ExtensionAirBuilder, MachineAir, SP1AirBuilder}; use std::borrow::BorrowMut; use tracing::instrument; -use crate::air::SP1RecursionAirBuilder; -use crate::memory::MemoryRecord; -use crate::runtime::{ExecutionRecord, RecursionProgram}; +use crate::{ + air::SP1RecursionAirBuilder, + memory::MemoryRecord, + runtime::{ExecutionRecord, RecursionProgram}, +}; pub const NUM_EXP_REVERSE_BITS_LEN_COLS: usize = core::mem::size_of::>(); @@ -74,11 +76,7 @@ impl ExpReverseBitsLenEvent { x: MemoryRecord::new_write( F::one(), Block::from([ - if i == len.as_canonical_u32() - 1 { - accum - } else { - x - }, + if i == len.as_canonical_u32() - 1 { accum } else { x }, F::zero(), F::zero(), F::zero(), @@ -136,10 +134,12 @@ pub struct ExpReverseBitsLenCols { /// The accumulator of the current iteration. pub accum: T, - /// A flag column to check whether the current row represents the last iteration of the computation. + /// A flag column to check whether the current row represents the last iteration of the + /// computation. pub is_last: IsZeroOperation, - /// A flag column to check whether the current row represents the first iteration of the computation. + /// A flag column to check whether the current row represents the first iteration of the + /// computation. pub is_first: IsZeroOperation, /// A column to count up from 0 to the length of the exponent. @@ -187,11 +187,8 @@ impl MachineAir for ExpReverseBitsLenCh _: &mut ExecutionRecord, ) -> RowMajorMatrix { let nb_events = input.exp_reverse_bits_len_events.len(); - let nb_rows = if self.pad { - next_power_of_two(nb_events, self.fixed_log2_rows) - } else { - nb_events - }; + let nb_rows = + if self.pad { next_power_of_two(nb_events, self.fixed_log2_rows) } else { nb_events }; let mut values = vec![F::zero(); nb_rows * NUM_EXP_REVERSE_BITS_LEN_COLS]; par_for_each_row(&mut values, NUM_EXP_REVERSE_BITS_LEN_COLS, |i, row| { @@ -256,33 +253,23 @@ impl ExpReverseBitsLenChip { ) { // Dummy constraints to normalize to DEGREE when DEGREE > 3. if DEGREE > 3 { - let lhs = (0..DEGREE) - .map(|_| local.is_real.into()) - .product::(); - let rhs = (0..DEGREE) - .map(|_| local.is_real.into()) - .product::(); + let lhs = (0..DEGREE).map(|_| local.is_real.into()).product::(); + let rhs = (0..DEGREE).map(|_| local.is_real.into()).product::(); builder.assert_eq(lhs, rhs); } // Constraint that the operands are sent from the CPU table. - let operands = [ - local.clk.into(), - local.base_ptr.into(), - local.ptr.into(), - local.len.into(), - ]; + let operands = + [local.clk.into(), local.base_ptr.into(), local.ptr.into(), local.len.into()]; builder.receive_table( Opcode::ExpReverseBitsLen.as_field::(), &operands, local.is_first.result, ); - // Make sure that local.is_first.result is not on for fake rows, so we don't receive operands - // for a fake row. - builder - .when_not(local.is_real) - .assert_zero(local.is_first.result); + // Make sure that local.is_first.result is not on for fake rows, so we don't receive + // operands for a fake row. + builder.when_not(local.is_real).assert_zero(local.is_first.result); IsZeroOperation::::eval( builder, @@ -299,9 +286,7 @@ impl ExpReverseBitsLenChip { ); // All real columns need to be in succession. - builder - .when_transition() - .assert_zero((AB::Expr::one() - local.is_real) * next.is_real); + builder.when_transition().assert_zero((AB::Expr::one() - local.is_real) * next.is_real); // Assert that the boolean columns are boolean. builder.assert_bool(local.is_real); @@ -321,9 +306,7 @@ impl ExpReverseBitsLenChip { .assert_one(next.is_first.result); // The accumulator needs to start with the multiplier for every `is_first` row. - builder - .when(local.is_first.result) - .assert_eq(local.accum, local.multiplier); + builder.when(local.is_first.result).assert_eq(local.accum, local.multiplier); // Assert that the last real row has `is_last` on. builder @@ -331,22 +314,17 @@ impl ExpReverseBitsLenChip { .when(local.is_real * (AB::Expr::one() - next.is_real)) .assert_one(local.is_last.result); - builder - .when_last_row() - .when(local.is_real) - .assert_one(local.is_last.result); + builder.when_last_row().when(local.is_real).assert_one(local.is_last.result); // `multiplier` is x if the current bit is 1, and 1 if the current bit is 0. - builder - .when(current_bit_val) - .assert_eq(local.multiplier, local.x.prev_value); + builder.when(current_bit_val).assert_eq(local.multiplier, local.x.prev_value); builder .when(local.is_real) .when_not(current_bit_val) .assert_eq(local.multiplier, AB::Expr::one()); - // To get `next.accum`, we multiply `local.prev_accum_squared` by `local.multiplier` when not - // `is_first`. + // To get `next.accum`, we multiply `local.prev_accum_squared` by `local.multiplier` when + // not `is_first`. builder .when_not(local.is_first.result) .assert_eq(local.accum, local.prev_accum_squared * local.multiplier); @@ -357,7 +335,8 @@ impl ExpReverseBitsLenChip { .when_not(local.is_last.result) .assert_eq(next.prev_accum_squared, local.accum * local.accum); - // Constrain the memory address `base_ptr` to be the same as the next, as long as not `is_last`. + // Constrain the memory address `base_ptr` to be the same as the next, as long as not + // `is_last`. builder .when_transition() .when_not(local.is_last.result) @@ -386,9 +365,7 @@ impl ExpReverseBitsLenChip { .assert_eq(local.iteration_num + AB::Expr::one(), next.iteration_num); // The `iteration_num` counter must be 0 iff `is_first` is on. - builder - .when(local.is_first.result) - .assert_eq(local.iteration_num, AB::Expr::zero()); + builder.when(local.is_first.result).assert_eq(local.iteration_num, AB::Expr::zero()); // Access the memory for current_bit. builder.recursion_eval_memory_access_single( @@ -406,9 +383,7 @@ impl ExpReverseBitsLenChip { ); // Make sure that x is only accessed when `is_real` is 1. - builder - .when_not(local.is_real) - .assert_zero(local.x_mem_access_flag); + builder.when_not(local.is_real).assert_zero(local.x_mem_access_flag); // Access the memory for x. // This only needs to be done for the first and last iterations. @@ -446,9 +421,7 @@ impl ExpReverseBitsLenChip { .assert_eq(local.x.access.value, local.x.prev_value); // Ensure that the value at the x memory access is `accum` when `is_last`. - builder - .when(local.is_last.result) - .assert_eq(local.accum, local.x.access.value); + builder.when(local.is_last.result).assert_eq(local.accum, local.x.access.value); } pub const fn do_exp_bit_memory_access(local: &ExpReverseBitsLenCols) -> T { @@ -477,33 +450,26 @@ where #[cfg(test)] mod tests { use itertools::Itertools; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use std::time::Instant; - use p3_baby_bear::BabyBear; - use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_field::AbstractField; use p3_matrix::{dense::RowMajorMatrix, Matrix}; - use p3_poseidon2::Poseidon2; - use p3_poseidon2::Poseidon2ExternalMatrixGeneral; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::{ - air::MachineAir, - utils::{uni_stark_prove, uni_stark_verify, BabyBearPoseidon2}, - }; + use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use sp1_core_machine::utils::{uni_stark_prove, uni_stark_verify}; - use crate::exp_reverse_bits::ExpReverseBitsLenChip; - use crate::exp_reverse_bits::ExpReverseBitsLenEvent; - use crate::runtime::ExecutionRecord; + use crate::{ + exp_reverse_bits::{ExpReverseBitsLenChip, ExpReverseBitsLenEvent}, + runtime::ExecutionRecord, + }; #[test] fn prove_babybear() { let config = BabyBearPoseidon2::compressed(); let mut challenger = config.challenger(); - let chip = ExpReverseBitsLenChip::<5> { - pad: true, - fixed_log2_rows: None, - }; + let chip = ExpReverseBitsLenChip::<5> { pad: true, fixed_log2_rows: None }; let test_xs = (1..16).map(BabyBear::from_canonical_u32).collect_vec(); @@ -519,17 +485,10 @@ mod tests { ); input_exec.exp_reverse_bits_len_events.append(&mut events); } - println!( - "input exec: {:?}", - input_exec.exp_reverse_bits_len_events.len() - ); + println!("input exec: {:?}", input_exec.exp_reverse_bits_len_events.len()); let trace: RowMajorMatrix = chip.generate_trace(&input_exec, &mut ExecutionRecord::::default()); - println!( - "trace dims is width: {:?}, height: {:?}", - trace.width(), - trace.height() - ); + println!("trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); let start = Instant::now(); let proof = uni_stark_prove(&config, &chip, &mut challenger, trace); diff --git a/recursion/core/src/fri_fold/mod.rs b/crates/recursion/core/src/fri_fold/mod.rs similarity index 82% rename from recursion/core/src/fri_fold/mod.rs rename to crates/recursion/core/src/fri_fold/mod.rs index 2631737920..cbde3e91db 100644 --- a/recursion/core/src/fri_fold/mod.rs +++ b/crates/recursion/core/src/fri_fold/mod.rs @@ -1,22 +1,24 @@ #![allow(clippy::needless_range_loop)] -use crate::memory::{MemoryReadCols, MemoryReadSingleCols, MemoryReadWriteCols}; -use crate::runtime::Opcode; +use crate::{ + memory::{MemoryReadCols, MemoryReadSingleCols, MemoryReadWriteCols}, + runtime::Opcode, +}; use core::borrow::Borrow; use p3_air::{Air, AirBuilder, BaseAir}; -use p3_field::AbstractField; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use sp1_core::air::{BaseAirBuilder, BinomialExtension, MachineAir}; -use sp1_core::utils::{next_power_of_two, par_for_each_row}; +use p3_field::{AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::{next_power_of_two, par_for_each_row}; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, BinomialExtension, MachineAir}; use std::borrow::BorrowMut; use tracing::instrument; -use crate::air::SP1RecursionAirBuilder; -use crate::memory::MemoryRecord; -use crate::runtime::{ExecutionRecord, RecursionProgram}; +use crate::{ + air::SP1RecursionAirBuilder, + memory::MemoryRecord, + runtime::{ExecutionRecord, RecursionProgram}, +}; pub const NUM_FRI_FOLD_COLS: usize = core::mem::size_of::>(); @@ -108,11 +110,8 @@ impl MachineAir for FriFoldChip _: &mut ExecutionRecord, ) -> RowMajorMatrix { let nb_events = input.fri_fold_events.len(); - let nb_rows = if self.pad { - next_power_of_two(nb_events, self.fixed_log2_rows) - } else { - nb_events - }; + let nb_rows = + if self.pad { next_power_of_two(nb_events, self.fixed_log2_rows) } else { nb_events }; let mut values = vec![F::zero(); nb_rows * NUM_FRI_FOLD_COLS]; par_for_each_row(&mut values, NUM_FRI_FOLD_COLS, |i, row| { @@ -140,8 +139,7 @@ impl MachineAir for FriFoldChip cols.p_at_x.populate(&event.p_at_x); cols.p_at_z.populate(&event.p_at_z); - cols.alpha_pow_at_log_height - .populate(&event.alpha_pow_at_log_height); + cols.alpha_pow_at_log_height.populate(&event.alpha_pow_at_log_height); cols.ro_at_log_height.populate(&event.ro_at_log_height); }); @@ -149,11 +147,7 @@ impl MachineAir for FriFoldChip let trace = RowMajorMatrix::new(values, NUM_FRI_FOLD_COLS); #[cfg(debug_assertions)] - println!( - "fri fold trace dims is width: {:?}, height: {:?}", - trace.width(), - trace.height() - ); + println!("fri fold trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); trace } @@ -175,17 +169,9 @@ impl FriFoldChip { // Constraint that the operands are sent from the CPU table. let first_iteration_clk = local.clk.into() - local.m.into(); let total_num_iterations = local.m.into() + AB::Expr::one(); - let operands = [ - first_iteration_clk, - total_num_iterations, - local.input_ptr.into(), - AB::Expr::zero(), - ]; - builder.receive_table( - Opcode::FRIFold.as_field::(), - &operands, - receive_table, - ); + let operands = + [first_iteration_clk, total_num_iterations, local.input_ptr.into(), AB::Expr::zero()]; + builder.receive_table(Opcode::FRIFold.as_field::(), &operands, receive_table); builder.assert_bool(local.is_last_iteration); builder.assert_bool(local.is_real); @@ -195,19 +181,11 @@ impl FriFoldChip { .when_not(local.is_last_iteration) .assert_eq(local.is_real, next.is_real); - builder - .when(local.is_last_iteration) - .assert_one(local.is_real); + builder.when(local.is_last_iteration).assert_one(local.is_real); - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when_not(local.is_real).assert_zero(next.is_real); - builder - .when_last_row() - .when_not(local.is_last_iteration) - .assert_zero(local.is_real); + builder.when_last_row().when_not(local.is_last_iteration).assert_zero(local.is_real); // Ensure that all first iteration rows has a m value of 0. builder.when_first_row().assert_zero(local.m); @@ -217,7 +195,8 @@ impl FriFoldChip { .when(next.is_real) .assert_zero(next.m); - // Ensure that all rows for a FRI FOLD invocation have the same input_ptr and sequential clk and m values. + // Ensure that all rows for a FRI FOLD invocation have the same input_ptr and sequential clk + // and m values. builder .when_transition() .when_not(local.is_last_iteration) @@ -325,20 +304,11 @@ impl FriFoldChip { // 2. Constrain new_value = old_value * alpha. let alpha = local.alpha.access.value.as_extension::(); - let alpha_pow_at_log_height = local - .alpha_pow_at_log_height - .prev_value - .as_extension::(); - let new_alpha_pow_at_log_height = local - .alpha_pow_at_log_height - .access - .value - .as_extension::(); + let alpha_pow_at_log_height = local.alpha_pow_at_log_height.prev_value.as_extension::(); + let new_alpha_pow_at_log_height = + local.alpha_pow_at_log_height.access.value.as_extension::(); - builder.assert_ext_eq( - alpha_pow_at_log_height.clone() * alpha, - new_alpha_pow_at_log_height, - ); + builder.assert_ext_eq(alpha_pow_at_log_height.clone() * alpha, new_alpha_pow_at_log_height); // Update ro_at_log_height. // 1. Constrain old and new value against memory. @@ -385,12 +355,8 @@ where let next: &FriFoldCols = (*next).borrow(); // Dummy constraints to normalize to DEGREE. - let lhs = (0..DEGREE) - .map(|_| local.is_real.into()) - .product::(); - let rhs = (0..DEGREE) - .map(|_| local.is_real.into()) - .product::(); + let lhs = (0..DEGREE).map(|_| local.is_real.into()).product::(); + let rhs = (0..DEGREE).map(|_| local.is_real.into()).product::(); builder.assert_eq(lhs, rhs); self.eval_fri_fold::( diff --git a/recursion/core/src/lib.rs b/crates/recursion/core/src/lib.rs similarity index 100% rename from recursion/core/src/lib.rs rename to crates/recursion/core/src/lib.rs diff --git a/recursion/core/src/memory/air.rs b/crates/recursion/core/src/memory/air.rs similarity index 79% rename from recursion/core/src/memory/air.rs rename to crates/recursion/core/src/memory/air.rs index 33d7c19df1..2b0257bcb8 100644 --- a/recursion/core/src/memory/air.rs +++ b/crates/recursion/core/src/memory/air.rs @@ -1,30 +1,28 @@ use core::mem::size_of; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField32}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use sp1_core::air::AirInteraction; -use sp1_core::air::MachineAir; -use sp1_core::lookup::InteractionKind; -use sp1_core::utils::next_power_of_two; -use sp1_core::utils::par_for_each_row; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::{next_power_of_two, par_for_each_row}; +use sp1_stark::{ + air::{AirInteraction, MachineAir}, + InteractionKind, +}; use std::borrow::{Borrow, BorrowMut}; use tracing::instrument; use super::columns::MemoryInitCols; -use crate::air::Block; -use crate::air::SP1RecursionAirBuilder; -use crate::memory::MemoryGlobalChip; -use crate::runtime::{ExecutionRecord, RecursionProgram}; +use crate::{ + air::{Block, SP1RecursionAirBuilder}, + memory::MemoryGlobalChip, + runtime::{ExecutionRecord, RecursionProgram}, +}; pub(crate) const NUM_MEMORY_INIT_COLS: usize = size_of::>(); #[allow(dead_code)] impl MemoryGlobalChip { pub const fn new() -> Self { - Self { - fixed_log2_rows: None, - } + Self { fixed_log2_rows: None } } } @@ -104,20 +102,17 @@ impl BaseAir for MemoryGlobalChip { } } -/// Computes the difference between the `addr` and `prev_addr` and returns the 16-bit limb and 12-bit -/// limbs of the difference. +/// Computes the difference between the `addr` and `prev_addr` and returns the 16-bit limb and +/// 12-bit limbs of the difference. /// -/// The parameter `subtract_one` is expected to be `true` when `addr` and `prev_addr` are consecutive -/// addresses in the global memory table (we don't allow repeated addresses), and `false` when this -/// function is used to perform the 28-bit range check on the `addr` field. +/// The parameter `subtract_one` is expected to be `true` when `addr` and `prev_addr` are +/// consecutive addresses in the global memory table (we don't allow repeated addresses), and +/// `false` when this function is used to perform the 28-bit range check on the `addr` field. pub fn compute_addr_diff(addr: F, prev_addr: F, subtract_one: bool) -> (F, F) { let diff = addr.as_canonical_u32() - prev_addr.as_canonical_u32() - subtract_one as u32; let diff_16bit_limb = diff & 0xffff; let diff_12bit_limb = (diff >> 16) & 0xfff; - ( - F::from_canonical_u32(diff_16bit_limb), - F::from_canonical_u32(diff_12bit_limb), - ) + (F::from_canonical_u32(diff_16bit_limb), F::from_canonical_u32(diff_12bit_limb)) } impl Air for MemoryGlobalChip @@ -159,24 +154,16 @@ where .assert_one(next.is_finalize + (AB::Expr::one() - next.is_real)); // After a padding row, we should only have another padding row. - builder - .when_transition() - .when(AB::Expr::one() - local.is_real) - .assert_zero(next.is_real); + builder.when_transition().when(AB::Expr::one() - local.is_real).assert_zero(next.is_real); // The last row should be a padding row or a finalize row. - builder - .when_last_row() - .assert_one(local.is_finalize + AB::Expr::one() - local.is_real); + builder.when_last_row().assert_one(local.is_finalize + AB::Expr::one() - local.is_real); // Ensure that the is_range_check column is properly computed. - // The flag column `is_range_check` is set iff is_finalize is set AND next.is_finalize is set. - builder - .when(local.is_range_check) - .assert_one(local.is_finalize * next.is_finalize); - builder - .when_not(local.is_range_check) - .assert_zero(local.is_finalize * next.is_finalize); + // The flag column `is_range_check` is set iff is_finalize is set AND next.is_finalize is + // set. + builder.when(local.is_range_check).assert_one(local.is_finalize * next.is_finalize); + builder.when_not(local.is_range_check).assert_zero(local.is_finalize * next.is_finalize); // Send requests for the 28-bit range checks and ensure that the limbs are correctly // computed. @@ -224,32 +211,23 @@ where #[cfg(test)] mod tests { use itertools::Itertools; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use std::time::Instant; - use p3_baby_bear::BabyBear; - use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_field::AbstractField; use p3_matrix::{dense::RowMajorMatrix, Matrix}; - use p3_poseidon2::Poseidon2; - use p3_poseidon2::Poseidon2ExternalMatrixGeneral; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::{ - air::MachineAir, - utils::{uni_stark_prove, uni_stark_verify, BabyBearPoseidon2}, - }; - - use crate::air::Block; - use crate::memory::MemoryGlobalChip; - use crate::runtime::ExecutionRecord; + use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use sp1_core_machine::utils::{uni_stark_prove, uni_stark_verify}; + + use crate::{air::Block, memory::MemoryGlobalChip, runtime::ExecutionRecord}; #[test] fn prove_babybear() { let config = BabyBearPoseidon2::compressed(); let mut challenger = config.challenger(); - let chip = MemoryGlobalChip { - fixed_log2_rows: None, - }; + let chip = MemoryGlobalChip { fixed_log2_rows: None }; let test_vals = (0..16).map(BabyBear::from_canonical_u32).collect_vec(); @@ -260,18 +238,12 @@ mod tests { } // Add a dummy initialize event because the AIR expects at least one. - input_exec - .first_memory_record - .push((BabyBear::zero(), Block::from(BabyBear::zero()))); + input_exec.first_memory_record.push((BabyBear::zero(), Block::from(BabyBear::zero()))); println!("input exec: {:?}", input_exec.last_memory_record.len()); let trace: RowMajorMatrix = chip.generate_trace(&input_exec, &mut ExecutionRecord::::default()); - println!( - "trace dims is width: {:?}, height: {:?}", - trace.width(), - trace.height() - ); + println!("trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); let start = Instant::now(); let proof = uni_stark_prove(&config, &chip, &mut challenger, trace); diff --git a/recursion/core/src/memory/columns.rs b/crates/recursion/core/src/memory/columns.rs similarity index 93% rename from recursion/core/src/memory/columns.rs rename to crates/recursion/core/src/memory/columns.rs index 0b83afa1e4..9145711873 100644 --- a/recursion/core/src/memory/columns.rs +++ b/crates/recursion/core/src/memory/columns.rs @@ -25,8 +25,8 @@ pub struct MemoryInitCols { // An additional column to indicate if the memory row is a padded row. pub is_real: T, - // A flag column for when range checks need to be applied to the diff columns. Range checks always - // need to be applied to the address columns. + // A flag column for when range checks need to be applied to the diff columns. Range checks + // always need to be applied to the address columns. pub is_range_check: T, } @@ -91,14 +91,16 @@ pub struct MemoryAccessCols { /// The previous timestamp that this memory access is being read from. pub prev_timestamp: T, - /// The following columns are decomposed limbs for the difference between the current access's timestamp - /// and the previous access's timestamp. Note the actual value of the timestamp is either the - /// accesses' shard or clk depending on the value of compare_clk. + /// The following columns are decomposed limbs for the difference between the current access's + /// timestamp and the previous access's timestamp. Note the actual value of the timestamp + /// is either the accesses' shard or clk depending on the value of compare_clk. - /// This column is the least significant 16 bit limb of current access timestamp - prev access timestamp. + /// This column is the least significant 16 bit limb of current access timestamp - prev access + /// timestamp. pub diff_16bit_limb: T, - /// This column is the most signficant 12 bit limb of current access timestamp - prev access timestamp. + /// This column is the most signficant 12 bit limb of current access timestamp - prev access + /// timestamp. pub diff_12bit_limb: T, } diff --git a/recursion/core/src/memory/mod.rs b/crates/recursion/core/src/memory/mod.rs similarity index 96% rename from recursion/core/src/memory/mod.rs rename to crates/recursion/core/src/memory/mod.rs index 08e56fb0cf..bde6d22b48 100644 --- a/recursion/core/src/memory/mod.rs +++ b/crates/recursion/core/src/memory/mod.rs @@ -29,10 +29,7 @@ fn compute_diff(timestamp: F, prev_timestamp: F) -> (F, F) { let diff_minus_one = timestamp.as_canonical_u32() - prev_timestamp.as_canonical_u32() - 1; let diff_16bit_limb = diff_minus_one & 0xffff; let diff_12bit_limb = (diff_minus_one >> 16) & 0xfff; - ( - F::from_canonical_u32(diff_16bit_limb), - F::from_canonical_u32(diff_12bit_limb), - ) + (F::from_canonical_u32(diff_16bit_limb), F::from_canonical_u32(diff_12bit_limb)) } impl MemoryRecord { diff --git a/recursion/core/src/multi/mod.rs b/crates/recursion/core/src/multi/mod.rs similarity index 80% rename from recursion/core/src/multi/mod.rs rename to crates/recursion/core/src/multi/mod.rs index c028fd5450..6c4cc566db 100644 --- a/recursion/core/src/multi/mod.rs +++ b/crates/recursion/core/src/multi/mod.rs @@ -1,22 +1,24 @@ -use std::array; -use std::borrow::{Borrow, BorrowMut}; -use std::cmp::max; -use std::ops::Deref; +use std::{ + array, + borrow::{Borrow, BorrowMut}, + cmp::max, + ops::Deref, +}; use itertools::Itertools; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField32}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use sp1_core::air::{BaseAirBuilder, MachineAir}; -use sp1_core::utils::pad_rows_fixed; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_rows_fixed; use sp1_derive::AlignedBorrow; +use sp1_stark::air::{BaseAirBuilder, MachineAir}; -use crate::air::{MultiBuilder, SP1RecursionAirBuilder}; -use crate::fri_fold::{FriFoldChip, FriFoldCols}; -use crate::poseidon2_wide::columns::Poseidon2; -use crate::poseidon2_wide::{Poseidon2WideChip, WIDTH}; -use crate::runtime::{ExecutionRecord, RecursionProgram}; +use crate::{ + air::{MultiBuilder, SP1RecursionAirBuilder}, + fri_fold::{FriFoldChip, FriFoldCols}, + poseidon2_wide::{columns::Poseidon2, Poseidon2WideChip, WIDTH}, + runtime::{ExecutionRecord, RecursionProgram}, +}; pub const NUM_MULTI_COLS: usize = core::mem::size_of::>(); @@ -47,7 +49,8 @@ pub struct MultiCols { /// Rows that needs to receive a poseidon2 syscall. pub poseidon2_receive_table: T, - /// Hash/Permute state entries that needs to access memory. This is for the the first half of the permute state. + /// Hash/Permute state entries that needs to access memory. This is for the the first half of + /// the permute state. pub poseidon2_1st_half_memory_access: [T; WIDTH / 2], /// Flag to indicate if all of the second half of a compress state needs to access memory. pub poseidon2_2nd_half_memory_access: T, @@ -78,14 +81,8 @@ impl MachineAir for MultiChip { input: &ExecutionRecord, output: &mut ExecutionRecord, ) -> RowMajorMatrix { - let fri_fold_chip = FriFoldChip:: { - fixed_log2_rows: None, - pad: false, - }; - let poseidon2 = Poseidon2WideChip:: { - fixed_log2_rows: None, - pad: false, - }; + let fri_fold_chip = FriFoldChip:: { fixed_log2_rows: None, pad: false }; + let poseidon2 = Poseidon2WideChip:: { fixed_log2_rows: None, pad: false }; let fri_fold_trace = fri_fold_chip.generate_trace(input, output); let mut poseidon2_trace = poseidon2.generate_trace(input, output); @@ -142,11 +139,7 @@ impl MachineAir for MultiChip { .collect_vec(); // Pad the trace to a power of two. - pad_rows_fixed( - &mut rows, - || vec![F::zero(); num_columns], - self.fixed_log2_rows, - ); + pad_rows_fixed(&mut rows, || vec![F::zero(); num_columns], self.fixed_log2_rows); // Convert the trace to a row major matrix. RowMajorMatrix::new(rows.into_iter().flatten().collect(), num_columns) @@ -172,12 +165,8 @@ where let next_multi_cols: &MultiCols = next_slice[0..NUM_MULTI_COLS].borrow(); // Dummy constraints to normalize to DEGREE. - let lhs = (0..DEGREE) - .map(|_| local_multi_cols.is_poseidon2.into()) - .product::(); - let rhs = (0..DEGREE) - .map(|_| local_multi_cols.is_poseidon2.into()) - .product::(); + let lhs = (0..DEGREE).map(|_| local_multi_cols.is_poseidon2.into()).product::(); + let rhs = (0..DEGREE).map(|_| local_multi_cols.is_poseidon2.into()).product::(); builder.assert_eq(lhs, rhs); let next_is_real = next_multi_cols.is_fri_fold + next_multi_cols.is_poseidon2; @@ -198,14 +187,12 @@ where local_multi_cols.is_fri_fold * (AB::Expr::one() - next_multi_cols.is_fri_fold), local_multi_cols.fri_fold_last_row, ); - builder.when_last_row().assert_eq( - local_multi_cols.is_fri_fold, - local_multi_cols.fri_fold_last_row, - ); - builder.when_first_row().assert_eq( - local_multi_cols.is_poseidon2, - local_multi_cols.poseidon2_first_row, - ); + builder + .when_last_row() + .assert_eq(local_multi_cols.is_fri_fold, local_multi_cols.fri_fold_last_row); + builder + .when_first_row() + .assert_eq(local_multi_cols.is_poseidon2, local_multi_cols.poseidon2_first_row); builder.when_transition().assert_eq( next_multi_cols.poseidon2_first_row, local_multi_cols.is_fri_fold * next_multi_cols.is_poseidon2, @@ -214,22 +201,20 @@ where local_multi_cols.is_poseidon2 * (AB::Expr::one() - next_multi_cols.is_poseidon2), local_multi_cols.poseidon2_last_row, ); - builder.when_last_row().assert_eq( - local_multi_cols.is_poseidon2, - local_multi_cols.poseidon2_last_row, - ); + builder + .when_last_row() + .assert_eq(local_multi_cols.is_poseidon2, local_multi_cols.poseidon2_last_row); - // Fri fold requires that it's rows are contiguous, since each invocation spans multiple rows - // and it's AIR checks for consistencies among them. The following constraints enforce that - // all the fri fold rows are first, then the posiedon2 rows, and finally any padded (non-real) rows. + // Fri fold requires that it's rows are contiguous, since each invocation spans multiple + // rows and it's AIR checks for consistencies among them. The following constraints + // enforce that all the fri fold rows are first, then the posiedon2 rows, and + // finally any padded (non-real) rows. // First verify that all real rows are contiguous. - builder - .when_transition() - .when_not(local_is_real.clone()) - .assert_zero(next_is_real.clone()); + builder.when_transition().when_not(local_is_real.clone()).assert_zero(next_is_real.clone()); - // Next, verify that all fri fold rows are before the poseidon2 rows within the real rows section. + // Next, verify that all fri fold rows are before the poseidon2 rows within the real rows + // section. builder .when_transition() .when(next_is_real) @@ -280,16 +265,14 @@ where local_multi_cols.is_poseidon2 * poseidon2_columns.control_flow().is_syscall_row, local_multi_cols.poseidon2_receive_table, ); - local_multi_cols - .poseidon2_1st_half_memory_access - .iter() - .enumerate() - .for_each(|(i, mem_access)| { + local_multi_cols.poseidon2_1st_half_memory_access.iter().enumerate().for_each( + |(i, mem_access)| { sub_builder.assert_eq( local_multi_cols.is_poseidon2 * poseidon2_columns.memory().memory_slot_used[i], *mem_access, ); - }); + }, + ); sub_builder.assert_eq( local_multi_cols.is_poseidon2 * poseidon2_columns.control_flow().is_compress, @@ -349,38 +332,28 @@ impl MultiChip { mod tests { use std::time::Instant; - use p3_baby_bear::BabyBear; - use p3_baby_bear::DiffusionMatrixBabyBear; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_matrix::{dense::RowMajorMatrix, Matrix}; - use p3_poseidon2::Poseidon2; - use p3_poseidon2::Poseidon2ExternalMatrixGeneral; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::{ - air::MachineAir, - utils::{uni_stark_prove, uni_stark_verify, BabyBearPoseidon2}, - }; + use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use sp1_core_machine::utils::{uni_stark_prove, uni_stark_verify}; + use sp1_stark::{air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; - use crate::multi::MultiChip; - use crate::poseidon2_wide::tests::generate_test_execution_record; - use crate::runtime::ExecutionRecord; + use crate::{ + multi::MultiChip, poseidon2_wide::tests::generate_test_execution_record, + runtime::ExecutionRecord, + }; #[test] fn prove_babybear() { let config = BabyBearPoseidon2::compressed(); let mut challenger = config.challenger(); - let chip = MultiChip::<9> { - fixed_log2_rows: None, - }; + let chip = MultiChip::<9> { fixed_log2_rows: None }; let input_exec = generate_test_execution_record(false); let trace: RowMajorMatrix = chip.generate_trace(&input_exec, &mut ExecutionRecord::::default()); - println!( - "trace dims is width: {:?}, height: {:?}", - trace.width(), - trace.height() - ); + println!("trace dims is width: {:?}, height: {:?}", trace.width(), trace.height()); let start = Instant::now(); let proof = uni_stark_prove(&config, &chip, &mut challenger, trace); diff --git a/recursion/core/src/poseidon2_wide/air/control_flow.rs b/crates/recursion/core/src/poseidon2_wide/air/control_flow.rs similarity index 80% rename from recursion/core/src/poseidon2_wide/air/control_flow.rs rename to crates/recursion/core/src/poseidon2_wide/air/control_flow.rs index 2b1f559bf3..6cd28028c1 100644 --- a/recursion/core/src/poseidon2_wide/air/control_flow.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/control_flow.rs @@ -1,6 +1,7 @@ use p3_air::AirBuilder; use p3_field::AbstractField; -use sp1_core::{air::BaseAirBuilder, operations::IsZeroOperation}; +use sp1_core_machine::operations::IsZeroOperation; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::SP1RecursionAirBuilder, @@ -63,9 +64,7 @@ impl Poseidon2WideChip { send_range_check, ); - builder - .when(local_control_flow.is_syscall_row) - .assert_one(local_is_real); + builder.when(local_control_flow.is_syscall_row).assert_one(local_is_real); } /// This function will verify that all hash rows are before the compress rows and that the first @@ -84,7 +83,8 @@ impl Poseidon2WideChip { local_is_real: AB::Expr, next_is_real: AB::Expr, ) { - // We require that the first row is an absorb syscall and that the hash_num == 0 and absorb_num == 0. + // We require that the first row is an absorb syscall and that the hash_num == 0 and + // absorb_num == 0. let mut first_row_builder = builder.when_first_row(); first_row_builder.assert_one(local_control_flow.is_absorb); first_row_builder.assert_one(local_control_flow.is_syscall_row); @@ -94,7 +94,8 @@ impl Poseidon2WideChip { // For absorb rows, constrain the following: // 1) when last absorb row, then the next row is a either an absorb or finalize syscall row. - // 2) when last absorb row and the next row is an absorb row, then absorb_num' = absorb_num + 1. + // 2) when last absorb row and the next row is an absorb row, then absorb_num' = absorb_num + // + 1. // 3) when not last absorb row, then the next row is an absorb non syscall row. // 4) when not last absorb row, then absorb_num' = absorb_num. // 5) hash_num == hash_num'. @@ -106,12 +107,10 @@ impl Poseidon2WideChip { absorb_last_row_builder .assert_one(next_control_flow.is_absorb + next_control_flow.is_finalize); absorb_last_row_builder.assert_one(next_control_flow.is_syscall_row); - absorb_last_row_builder - .when(next_control_flow.is_absorb) - .assert_eq( - next_opcode_workspace.absorb().absorb_num, - local_opcode_workspace.absorb().absorb_num + AB::Expr::one(), - ); + absorb_last_row_builder.when(next_control_flow.is_absorb).assert_eq( + next_opcode_workspace.absorb().absorb_num, + local_opcode_workspace.absorb().absorb_num + AB::Expr::one(), + ); let mut absorb_not_last_row_builder = transition_builder.when(local_control_flow.is_absorb_not_last_row); @@ -124,18 +123,14 @@ impl Poseidon2WideChip { let mut absorb_transition_builder = transition_builder.when(local_control_flow.is_absorb); - absorb_transition_builder - .when(next_control_flow.is_absorb) - .assert_eq( - local_opcode_workspace.absorb().hash_num, - next_opcode_workspace.absorb().hash_num, - ); - absorb_transition_builder - .when(next_control_flow.is_finalize) - .assert_eq( - local_opcode_workspace.absorb().hash_num, - next_syscall_params.finalize().hash_num, - ); + absorb_transition_builder.when(next_control_flow.is_absorb).assert_eq( + local_opcode_workspace.absorb().hash_num, + next_opcode_workspace.absorb().hash_num, + ); + absorb_transition_builder.when(next_control_flow.is_finalize).assert_eq( + local_opcode_workspace.absorb().hash_num, + next_syscall_params.finalize().hash_num, + ); } // For finalize rows, constrain the following: @@ -152,12 +147,10 @@ impl Poseidon2WideChip { .assert_one(next_control_flow.is_absorb + next_control_flow.is_compress); finalize_transition_builder.assert_one(next_control_flow.is_syscall_row); - finalize_transition_builder - .when(next_control_flow.is_absorb) - .assert_eq( - local_syscall_params.finalize().hash_num + AB::Expr::one(), - next_opcode_workspace.absorb().hash_num, - ); + finalize_transition_builder.when(next_control_flow.is_absorb).assert_eq( + local_syscall_params.finalize().hash_num + AB::Expr::one(), + next_opcode_workspace.absorb().hash_num, + ); finalize_transition_builder .when(next_control_flow.is_absorb) .assert_zero(next_opcode_workspace.absorb().absorb_num); @@ -183,13 +176,12 @@ impl Poseidon2WideChip { .when(local_control_flow.is_syscall_row) .assert_one(next_control_flow.is_compress_output); - // When we are at a compress output row, then ensure next row is either not real or is a compress syscall row. - transition_builder - .when(local_control_flow.is_compress_output) - .assert_one( - (AB::Expr::one() - next_is_real.clone()) - + next_control_flow.is_compress * next_control_flow.is_syscall_row, - ); + // When we are at a compress output row, then ensure next row is either not real or is a + // compress syscall row. + transition_builder.when(local_control_flow.is_compress_output).assert_one( + (AB::Expr::one() - next_is_real.clone()) + + next_control_flow.is_compress * next_control_flow.is_syscall_row, + ); } // Constrain that there is only one is_real -> not is real transition. Also contrain that @@ -197,9 +189,7 @@ impl Poseidon2WideChip { { let mut transition_builder = builder.when_transition(); - transition_builder - .when_not(local_is_real.clone()) - .assert_zero(next_is_real.clone()); + transition_builder.when_not(local_is_real.clone()).assert_zero(next_is_real.clone()); transition_builder .when(local_is_real.clone()) @@ -230,7 +220,8 @@ impl Poseidon2WideChip { // Verify that the hash_num and absorb_num are correctly decomposed from the syscall // hash_and_absorb_num param. - // Also range check that both hash_num is within [0, 2^16 - 1] and absorb_num is within [0, 2^12 - 1]; + // Also range check that both hash_num is within [0, 2^16 - 1] and absorb_num is within [0, + // 2^12 - 1]; { let mut absorb_builder = builder.when(local_control_flow.is_absorb); @@ -301,22 +292,21 @@ impl Poseidon2WideChip { ); } - // For the absorb syscall row, ensure correct value of num_remaining_rows, last_row_num_consumed, - // and num_remaining_rows_is_zero. + // For the absorb syscall row, ensure correct value of num_remaining_rows, + // last_row_num_consumed, and num_remaining_rows_is_zero. { let mut absorb_builder = builder.when(local_control_flow.is_absorb); - // Verify that state_cursor + syscall input_len - 1 == num_remaining_rows * RATE + last_row_ending_cursor. - // The minus one is needed, since `last_row_ending_cursor` is inclusive of the last element, + // Verify that state_cursor + syscall input_len - 1 == num_remaining_rows * RATE + + // last_row_ending_cursor. The minus one is needed, since + // `last_row_ending_cursor` is inclusive of the last element, // while state_cursor + syscall input_len is not. - absorb_builder - .when(local_control_flow.is_syscall_row) - .assert_eq( - local_hash_workspace.state_cursor + local_syscall_params.absorb().input_len - - AB::Expr::one(), - local_hash_workspace.num_remaining_rows * AB::Expr::from_canonical_usize(RATE) - + local_hash_workspace.last_row_ending_cursor, - ); + absorb_builder.when(local_control_flow.is_syscall_row).assert_eq( + local_hash_workspace.state_cursor + local_syscall_params.absorb().input_len + - AB::Expr::one(), + local_hash_workspace.num_remaining_rows * AB::Expr::from_canonical_usize(RATE) + + local_hash_workspace.last_row_ending_cursor, + ); // Range check that last_row_ending_cursor is between [0, 7]. (0..3).for_each(|i| { @@ -328,16 +318,14 @@ impl Poseidon2WideChip { .zip(0..3) .map(|(bit, exp)| *bit * AB::Expr::from_canonical_u32(2u32.pow(exp))) .sum::(); - absorb_builder - .when(local_control_flow.is_syscall_row) - .assert_eq( - local_hash_workspace.last_row_ending_cursor, - expected_last_row_ending_cursor, - ); + absorb_builder.when(local_control_flow.is_syscall_row).assert_eq( + local_hash_workspace.last_row_ending_cursor, + expected_last_row_ending_cursor, + ); - // Range check that input_len < 2^16. This check is only needed for absorb syscall rows, - // but we send it for all absorb rows, since the `is_real` parameter must be an expression - // with at most degree 1. + // Range check that input_len < 2^16. This check is only needed for absorb syscall + // rows, but we send it for all absorb rows, since the `is_real` parameter + // must be an expression with at most degree 1. builder.send_range_check( AB::Expr::from_canonical_u8(RangeCheckOpcode::U16 as u8), local_syscall_params.absorb().input_len, @@ -359,26 +347,22 @@ impl Poseidon2WideChip { let mut absorb_transition_builder = transition_builder.when(local_control_flow.is_absorb); - absorb_transition_builder - .when_not(local_hash_workspace.is_last_row::()) - .assert_eq( - next_hash_workspace.num_remaining_rows, - local_hash_workspace.num_remaining_rows - AB::Expr::one(), - ); + absorb_transition_builder.when_not(local_hash_workspace.is_last_row::()).assert_eq( + next_hash_workspace.num_remaining_rows, + local_hash_workspace.num_remaining_rows - AB::Expr::one(), + ); // Copy down the last_row_ending_cursor value within the absorb call. - absorb_transition_builder - .when_not(local_hash_workspace.is_last_row::()) - .assert_eq( - next_hash_workspace.last_row_ending_cursor, - local_hash_workspace.last_row_ending_cursor, - ); + absorb_transition_builder.when_not(local_hash_workspace.is_last_row::()).assert_eq( + next_hash_workspace.last_row_ending_cursor, + local_hash_workspace.last_row_ending_cursor, + ); } // Constrain the state cursor. There are three constraints: // 1) For the first hash row, verify that state_cursor == 0. - // 2) For the last absorb rows, verify that constrain - // state_cursor' = (last_row_ending_cursor + 1) % RATE. + // 2) For the last absorb rows, verify that constrain state_cursor' = + // (last_row_ending_cursor + 1) % RATE. // 3) For all non syscall rows, the state_cursor should be 0. { let mut absorb_builder = builder.when(local_control_flow.is_absorb); diff --git a/recursion/core/src/poseidon2_wide/air/memory.rs b/crates/recursion/core/src/poseidon2_wide/air/memory.rs similarity index 83% rename from recursion/core/src/poseidon2_wide/air/memory.rs rename to crates/recursion/core/src/poseidon2_wide/air/memory.rs index 3df855d164..4d4e783972 100644 --- a/recursion/core/src/poseidon2_wide/air/memory.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/memory.rs @@ -1,6 +1,6 @@ use p3_air::AirBuilder; use p3_field::AbstractField; -use sp1_core::air::BaseAirBuilder; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::SP1RecursionAirBuilder, @@ -35,19 +35,17 @@ impl Poseidon2WideChip { for i in 0..WIDTH / 2 { builder.assert_bool(local_memory.memory_slot_used[i]); - // The memory slot flag will be used as the memory access multiplicity flag, so we need to - // ensure that those values are zero for all non real rows. - builder - .when_not(is_real.clone()) - .assert_zero(local_memory.memory_slot_used[i]); + // The memory slot flag will be used as the memory access multiplicity flag, so we need + // to ensure that those values are zero for all non real rows. + builder.when_not(is_real.clone()).assert_zero(local_memory.memory_slot_used[i]); // For compress and finalize, all of the slots should be true. builder .when(control_flow.is_compress + control_flow.is_finalize) .assert_one(local_memory.memory_slot_used[i]); - // For absorb, need to make sure the memory_slots_used is consistent with the start_cursor and - // end_cursor (i.e. start_cursor + num_consumed); + // For absorb, need to make sure the memory_slots_used is consistent with the + // start_cursor and end_cursor (i.e. start_cursor + num_consumed); self.eval_absorb_memory_slots(builder, control_flow, local_memory, opcode_workspace); } @@ -64,7 +62,8 @@ impl Poseidon2WideChip { .assert_eq(syscall_params.compress().dst_ptr, local_memory.start_addr); // For absorb syscall rows, the start_addr should initially be from the syscall param's - // input_ptr, and for subsequent rows, it's incremented by the number of consumed elements. + // input_ptr, and for subsequent rows, it's incremented by the number of consumed + // elements. builder .when(control_flow.is_absorb) .when(control_flow.is_syscall_row) @@ -75,10 +74,9 @@ impl Poseidon2WideChip { ); // For finalize syscall rows, the start_addr should be the param's output ptr. - builder.when(control_flow.is_finalize).assert_eq( - syscall_params.finalize().output_ptr, - local_memory.start_addr, - ); + builder + .when(control_flow.is_finalize) + .assert_eq(syscall_params.finalize().output_ptr, local_memory.start_addr); } // Contrain memory access for the first half of the memory accesses. @@ -94,12 +92,10 @@ impl Poseidon2WideChip { let compress_syscall_row = control_flow.is_compress * control_flow.is_syscall_row; // For read only accesses, assert the value didn't change. - builder - .when(compress_syscall_row + control_flow.is_absorb) - .assert_eq( - *local_memory.memory_accesses[i].prev_value(), - *local_memory.memory_accesses[i].value(), - ); + builder.when(compress_syscall_row + control_flow.is_absorb).assert_eq( + *local_memory.memory_accesses[i].prev_value(), + *local_memory.memory_accesses[i].value(), + ); addr = addr.clone() + local_memory.memory_slot_used[i].into(); } @@ -111,10 +107,9 @@ impl Poseidon2WideChip { // Verify the start addr. let is_compress_syscall = control_flow.is_compress * control_flow.is_syscall_row; - builder.when(is_compress_syscall.clone()).assert_eq( - compress_workspace.start_addr, - syscall_params.compress().right_ptr, - ); + builder + .when(is_compress_syscall.clone()) + .assert_eq(compress_workspace.start_addr, syscall_params.compress().right_ptr); builder.when(control_flow.is_compress_output).assert_eq( compress_workspace.start_addr, syscall_params.compress().dst_ptr + AB::Expr::from_canonical_usize(WIDTH / 2), @@ -147,11 +142,13 @@ impl Poseidon2WideChip { local_memory: &Memory, opcode_workspace: &OpcodeWorkspace, ) { - // To verify that the absorb memory slots are correct, we take the derivative of the memory slots, - // (e.g. memory_slot_used[i] - memory_slot_used[i - 1]), and assert the following: + // To verify that the absorb memory slots are correct, we take the derivative of the memory + // slots, (e.g. memory_slot_used[i] - memory_slot_used[i - 1]), and assert the + // following: // 1) when start_mem_idx_bitmap[i] == 1 -> derivative == 1 // 2) when end_mem_idx_bitmap[i + 1] == 1 -> derivative == -1 - // 3) when start_mem_idx_bitmap[i] == 0 and end_mem_idx_bitmap[i + 1] == 0 -> derivative == 0 + // 3) when start_mem_idx_bitmap[i] == 0 and end_mem_idx_bitmap[i + 1] == 0 -> derivative == + // 0 let mut absorb_builder = builder.when(control_flow.is_absorb); let start_mem_idx_bitmap = opcode_workspace.absorb().start_mem_idx_bitmap; @@ -165,15 +162,10 @@ impl Poseidon2WideChip { let is_start_mem_idx = start_mem_idx_bitmap[i].into(); - let is_previous_end_mem_idx = if i == 0 { - AB::Expr::zero() - } else { - end_mem_idx_bitmap[i - 1].into() - }; + let is_previous_end_mem_idx = + if i == 0 { AB::Expr::zero() } else { end_mem_idx_bitmap[i - 1].into() }; - absorb_builder - .when(is_start_mem_idx.clone()) - .assert_one(derivative.clone()); + absorb_builder.when(is_start_mem_idx.clone()).assert_one(derivative.clone()); absorb_builder .when(is_previous_end_mem_idx.clone()) @@ -223,9 +215,6 @@ impl Poseidon2WideChip { // When we are in the last row, end_mem_idx bitmap should equal last_row_ending_cursor. absorb_builder .when(opcode_workspace.absorb().is_last_row::()) - .assert_eq( - end_mem_idx, - opcode_workspace.absorb().last_row_ending_cursor, - ); + .assert_eq(end_mem_idx, opcode_workspace.absorb().last_row_ending_cursor); } } diff --git a/recursion/core/src/poseidon2_wide/air/mod.rs b/crates/recursion/core/src/poseidon2_wide/air/mod.rs similarity index 91% rename from recursion/core/src/poseidon2_wide/air/mod.rs rename to crates/recursion/core/src/poseidon2_wide/air/mod.rs index 5780b195a5..c121103e50 100644 --- a/recursion/core/src/poseidon2_wide/air/mod.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/mod.rs @@ -22,22 +22,23 @@ //! # Absorb rows //! //! For absorb rows, the AIR needs to ensure that all of the input is written into the hash state -//! and that its written into the correct parts of that state. To do this, the AIR will first ensure -//! the correct values for num_remaining_rows (e.g. total number of rows of an absorb syscall) and -//! the last_row_ending_cursor. It does this by checking the following: +//! and that its written into the correct parts of that state. To do this, the AIR will first +//! ensure the correct values for num_remaining_rows (e.g. total number of rows of an absorb +//! syscall) and the last_row_ending_cursor. It does this by checking the following: //! //! 1. start_state_cursor + syscall_input_len == num_remaining_rows * RATE + last_row_ending_cursor //! 2. range check syscall_input_len to be [0, 2^16 - 1] //! 3. range check last_row_ending_cursor to be [0, RATE] //! //! For all subsequent absorb rows, the num_remaining_rows will be decremented by 1, and the -//! last_row_ending_cursor will be copied down to all of the rows. Also, for the next absorb/finalize -//! syscall, its state_cursor is set to (last_row_ending_cursor + 1) % RATE. +//! last_row_ending_cursor will be copied down to all of the rows. Also, for the next +//! absorb/finalize syscall, its state_cursor is set to (last_row_ending_cursor + 1) % RATE. //! //! From num_remaining_rows and syscall column, we know the absorb's first row and last row. //! From that fact, we can then enforce the following state writes. //! -//! 1. is_first_row && is_last_row -> state writes are [state_cursor..state_cursor + last_row_ending_cursor] +//! 1. is_first_row && is_last_row -> state writes are [state_cursor..state_cursor + +//! last_row_ending_cursor] //! 2. is_first_row && !is_last_row -> state writes are [state_cursor..RATE - 1] //! 3. !is_first_row && !is_last_row -> state writes are [0..RATE - 1] //! 4. !is_first_row && is_last_row -> state writes are [0..last_row_ending_cursor] @@ -111,12 +112,10 @@ where let next_row = Self::convert::(main.row_slice(1)); // Dummy constraints to normalize to DEGREE. - let lhs = (0..DEGREE) - .map(|_| local_row.control_flow().is_compress.into()) - .product::(); - let rhs = (0..DEGREE) - .map(|_| local_row.control_flow().is_compress.into()) - .product::(); + let lhs = + (0..DEGREE).map(|_| local_row.control_flow().is_compress.into()).product::(); + let rhs = + (0..DEGREE).map(|_| local_row.control_flow().is_compress.into()).product::(); builder.assert_eq(lhs, rhs); self.eval_poseidon2( diff --git a/recursion/core/src/poseidon2_wide/air/permutation.rs b/crates/recursion/core/src/poseidon2_wide/air/permutation.rs similarity index 93% rename from recursion/core/src/poseidon2_wide/air/permutation.rs rename to crates/recursion/core/src/poseidon2_wide/air/permutation.rs index c9920a8a2e..673a5c50dc 100644 --- a/recursion/core/src/poseidon2_wide/air/permutation.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/permutation.rs @@ -27,8 +27,8 @@ impl Poseidon2WideChip { ) { // Construct the input array of the permutation. That array is dependent on the row type. // For compress_syscall rows, the input is from the memory access values. For absorb, the - // input is the previous state, with select elements being read from the memory access values. - // For finalize, the input is the previous state. + // input is the previous state, with select elements being read from the memory access + // values. For finalize, the input is the previous state. let input: [AB::Expr; WIDTH] = array::from_fn(|i| { let previous_state = opcode_workspace.absorb().previous_state[i]; @@ -91,11 +91,7 @@ impl Poseidon2WideChip { let external_state = perm_cols.external_rounds_state()[r]; // Add the round constants. - let round = if r < NUM_EXTERNAL_ROUNDS / 2 { - r - } else { - r + NUM_INTERNAL_ROUNDS - }; + let round = if r < NUM_EXTERNAL_ROUNDS / 2 { r } else { r + NUM_INTERNAL_ROUNDS }; let add_rc: [AB::Expr; WIDTH] = core::array::from_fn(|i| { external_state[i].into() + AB::F::from_wrapped_u32(RC_16_30_U32[round][i]) }); @@ -144,11 +140,8 @@ impl Poseidon2WideChip { for r in 0..NUM_INTERNAL_ROUNDS { // Add the round constant. let round = r + NUM_EXTERNAL_ROUNDS / 2; - let add_rc = if r == 0 { - state[0].clone() - } else { - s0[r - 1].into() - } + AB::Expr::from_wrapped_u32(RC_16_30_U32[round][0]); + let add_rc = if r == 0 { state[0].clone() } else { s0[r - 1].into() } + + AB::Expr::from_wrapped_u32(RC_16_30_U32[round][0]); let mut sbox_deg_3 = add_rc.clone() * add_rc.clone() * add_rc.clone(); if let Some(internal_sbox) = perm_cols.internal_rounds_sbox() { @@ -156,7 +149,8 @@ impl Poseidon2WideChip { sbox_deg_3 = internal_sbox[r].into(); } - // See `populate_internal_rounds` for why we don't have columns for the sbox output here. + // See `populate_internal_rounds` for why we don't have columns for the sbox output + // here. let sbox_deg_7 = sbox_deg_3.clone() * sbox_deg_3.clone() * add_rc.clone(); // Apply the linear layer. diff --git a/recursion/core/src/poseidon2_wide/air/state_transition.rs b/crates/recursion/core/src/poseidon2_wide/air/state_transition.rs similarity index 83% rename from recursion/core/src/poseidon2_wide/air/state_transition.rs rename to crates/recursion/core/src/poseidon2_wide/air/state_transition.rs index 1b4b522a5d..0780245b6a 100644 --- a/recursion/core/src/poseidon2_wide/air/state_transition.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/state_transition.rs @@ -1,7 +1,7 @@ use std::array; use p3_air::AirBuilder; -use sp1_core::{air::BaseAirBuilder, utils::DIGEST_SIZE}; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::SP1RecursionAirBuilder, @@ -13,6 +13,7 @@ use crate::{ }, Poseidon2WideChip, WIDTH, }, + runtime::DIGEST_SIZE, }; impl Poseidon2WideChip { @@ -53,14 +54,12 @@ impl Poseidon2WideChip { .when(local_opcode_workspace.absorb().is_first_hash_row) .assert_all_zero(local_opcode_workspace.absorb().previous_state); - // Check that the state is equal to the permutation output when the permutation is applied. + // Check that the state is equal to the permutation output when the permutation is + // applied. builder .when(control_flow.is_absorb) .when(local_opcode_workspace.absorb().do_perm::()) - .assert_all_eq( - local_opcode_workspace.absorb().state, - *permutation.perm_output(), - ); + .assert_all_eq(local_opcode_workspace.absorb().state, *permutation.perm_output()); // Construct the input into the permutation. let input: [AB::Expr; WIDTH] = array::from_fn(|i| { @@ -75,33 +74,30 @@ impl Poseidon2WideChip { } }); - // Check that the state is equal the the permutation input when the permutation is not applied. + // Check that the state is equal the the permutation input when the permutation is not + // applied. builder .when(control_flow.is_absorb_no_perm) .assert_all_eq(local_opcode_workspace.absorb().state, input); // Check that the state is copied to the next row. - builder - .when_transition() - .when(control_flow.is_absorb) - .assert_all_eq( - local_opcode_workspace.absorb().state, - next_opcode_workspace.absorb().previous_state, - ); + builder.when_transition().when(control_flow.is_absorb).assert_all_eq( + local_opcode_workspace.absorb().state, + next_opcode_workspace.absorb().previous_state, + ); } // Finalize rows. { - // Check that the state is equal to the permutation output when the permutation is applied. + // Check that the state is equal to the permutation output when the permutation is + // applied. builder .when(control_flow.is_finalize) .when(local_opcode_workspace.finalize().do_perm::()) - .assert_all_eq( - local_opcode_workspace.finalize().state, - *permutation.perm_output(), - ); + .assert_all_eq(local_opcode_workspace.finalize().state, *permutation.perm_output()); - // Check that the state is equal to the previous state when the permutation is not applied. + // Check that the state is equal to the previous state when the permutation is not + // applied. builder .when(control_flow.is_finalize) .when_not(local_opcode_workspace.finalize().do_perm::()) diff --git a/recursion/core/src/poseidon2_wide/air/syscall_params.rs b/crates/recursion/core/src/poseidon2_wide/air/syscall_params.rs similarity index 79% rename from recursion/core/src/poseidon2_wide/air/syscall_params.rs rename to crates/recursion/core/src/poseidon2_wide/air/syscall_params.rs index a79878e0ac..c33e99fa5e 100644 --- a/recursion/core/src/poseidon2_wide/air/syscall_params.rs +++ b/crates/recursion/core/src/poseidon2_wide/air/syscall_params.rs @@ -1,5 +1,5 @@ use p3_air::AirBuilder; -use sp1_core::air::BaseAirBuilder; +use sp1_stark::air::BaseAirBuilder; use crate::{ air::SP1RecursionAirBuilder, @@ -23,12 +23,9 @@ impl Poseidon2WideChip { ) { // Constraint that the operands are sent from the CPU table. let params = local_syscall.get_raw_params(); - let opcodes: [AB::Expr; 3] = [ - Opcode::Poseidon2Compress, - Opcode::Poseidon2Absorb, - Opcode::Poseidon2Finalize, - ] - .map(|x| x.as_field::().into()); + let opcodes: [AB::Expr; 3] = + [Opcode::Poseidon2Compress, Opcode::Poseidon2Absorb, Opcode::Poseidon2Finalize] + .map(|x| x.as_field::().into()); let opcode_selectors = [ local_control_flow.is_compress, local_control_flow.is_absorb, @@ -57,10 +54,8 @@ impl Poseidon2WideChip { .assert_eq(local_syscall_params.dst_ptr, next_syscall_params.dst_ptr); compress_syscall_builder .assert_eq(local_syscall_params.left_ptr, next_syscall_params.left_ptr); - compress_syscall_builder.assert_eq( - local_syscall_params.right_ptr, - next_syscall_params.right_ptr, - ); + compress_syscall_builder + .assert_eq(local_syscall_params.right_ptr, next_syscall_params.right_ptr); } // Verify that the syscall parameters are copied down to all the non syscall absorb rows. @@ -77,14 +72,10 @@ impl Poseidon2WideChip { local_syscall_params.hash_and_absorb_num, next_syscall_params.hash_and_absorb_num, ); - absorb_syscall_builder.assert_eq( - local_syscall_params.input_ptr, - next_syscall_params.input_ptr, - ); - absorb_syscall_builder.assert_eq( - local_syscall_params.input_len, - next_syscall_params.input_len, - ); + absorb_syscall_builder + .assert_eq(local_syscall_params.input_ptr, next_syscall_params.input_ptr); + absorb_syscall_builder + .assert_eq(local_syscall_params.input_len, next_syscall_params.input_len); } } } diff --git a/recursion/core/src/poseidon2_wide/columns/control_flow.rs b/crates/recursion/core/src/poseidon2_wide/columns/control_flow.rs similarity index 100% rename from recursion/core/src/poseidon2_wide/columns/control_flow.rs rename to crates/recursion/core/src/poseidon2_wide/columns/control_flow.rs diff --git a/recursion/core/src/poseidon2_wide/columns/memory.rs b/crates/recursion/core/src/poseidon2_wide/columns/memory.rs similarity index 100% rename from recursion/core/src/poseidon2_wide/columns/memory.rs rename to crates/recursion/core/src/poseidon2_wide/columns/memory.rs diff --git a/recursion/core/src/poseidon2_wide/columns/mod.rs b/crates/recursion/core/src/poseidon2_wide/columns/mod.rs similarity index 99% rename from recursion/core/src/poseidon2_wide/columns/mod.rs rename to crates/recursion/core/src/poseidon2_wide/columns/mod.rs index eafda7b4d6..886002d378 100644 --- a/recursion/core/src/poseidon2_wide/columns/mod.rs +++ b/crates/recursion/core/src/poseidon2_wide/columns/mod.rs @@ -1,6 +1,6 @@ use std::mem::{size_of, transmute}; -use sp1_core::utils::indices_arr; +use sp1_core_machine::utils::indices_arr; use sp1_derive::AlignedBorrow; use self::{ diff --git a/recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs b/crates/recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs similarity index 93% rename from recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs rename to crates/recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs index 3ff574f3c6..a208065f21 100644 --- a/recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs +++ b/crates/recursion/core/src/poseidon2_wide/columns/opcode_workspace.rs @@ -1,5 +1,5 @@ use p3_field::AbstractField; -use sp1_core::operations::IsZeroOperation; +use sp1_core_machine::operations::IsZeroOperation; use sp1_derive::AlignedBorrow; use crate::{ @@ -74,7 +74,9 @@ pub struct AbsorbWorkspace { /// This is the state index of that last element consumed by the absorb syscall. pub last_row_ending_cursor: T, - pub last_row_ending_cursor_is_seven: IsZeroOperation, // Needed when doing the (last_row_ending_cursor_is_seven + 1) % 8 calculation. + pub last_row_ending_cursor_is_seven: IsZeroOperation, /* Needed when doing the + * (last_row_ending_cursor_is_seven + * + 1) % 8 calculation. */ pub last_row_ending_cursor_bitmap: [T; 3], /// Materialized control flow flags to deal with max contraint degree. diff --git a/recursion/core/src/poseidon2_wide/columns/permutation.rs b/crates/recursion/core/src/poseidon2_wide/columns/permutation.rs similarity index 96% rename from recursion/core/src/poseidon2_wide/columns/permutation.rs rename to crates/recursion/core/src/poseidon2_wide/columns/permutation.rs index caaab08fd0..01db4fbed9 100644 --- a/recursion/core/src/poseidon2_wide/columns/permutation.rs +++ b/crates/recursion/core/src/poseidon2_wide/columns/permutation.rs @@ -219,16 +219,12 @@ where T: Copy, { if DEGREE == 3 { - let start = POSEIDON2_DEGREE3_COL_MAP - .permutation_cols - .external_rounds_state[0][0]; + let start = POSEIDON2_DEGREE3_COL_MAP.permutation_cols.external_rounds_state[0][0]; let end = start + size_of::>(); let convert: &mut PermutationSBox = row[start..end].borrow_mut(); Box::new(convert) } else if DEGREE == 9 || DEGREE == 17 { - let start = POSEIDON2_DEGREE9_COL_MAP - .permutation_cols - .external_rounds_state[0][0]; + let start = POSEIDON2_DEGREE9_COL_MAP.permutation_cols.external_rounds_state[0][0]; let end = start + size_of::>(); let convert: &mut PermutationNoSbox = row[start..end].borrow_mut(); diff --git a/recursion/core/src/poseidon2_wide/columns/syscall_params.rs b/crates/recursion/core/src/poseidon2_wide/columns/syscall_params.rs similarity index 93% rename from recursion/core/src/poseidon2_wide/columns/syscall_params.rs rename to crates/recursion/core/src/poseidon2_wide/columns/syscall_params.rs index 7550cfb8a5..cca164ceb5 100644 --- a/recursion/core/src/poseidon2_wide/columns/syscall_params.rs +++ b/crates/recursion/core/src/poseidon2_wide/columns/syscall_params.rs @@ -45,12 +45,7 @@ impl SyscallParams { // All of the union's fields should have the same size, so just choose one of them to return // the elements. let compress = self.compress(); - [ - compress.clk, - compress.dst_ptr, - compress.left_ptr, - compress.right_ptr, - ] + [compress.clk, compress.dst_ptr, compress.left_ptr, compress.right_ptr] } } diff --git a/recursion/core/src/poseidon2_wide/events.rs b/crates/recursion/core/src/poseidon2_wide/events.rs similarity index 95% rename from recursion/core/src/poseidon2_wide/events.rs rename to crates/recursion/core/src/poseidon2_wide/events.rs index 83e22415b2..d1e66096a8 100644 --- a/recursion/core/src/poseidon2_wide/events.rs +++ b/crates/recursion/core/src/poseidon2_wide/events.rs @@ -1,9 +1,7 @@ use p3_field::PrimeField32; use p3_symmetric::Permutation; -use crate::memory::MemoryRecord; -use crate::poseidon2_wide::WIDTH; -use crate::runtime::DIGEST_SIZE; +use crate::{memory::MemoryRecord, poseidon2_wide::WIDTH, runtime::DIGEST_SIZE}; use super::RATE; @@ -67,7 +65,8 @@ impl Poseidon2AbsorbEvent { permuter: &impl Permutation<[F; WIDTH]>, hash_state: &mut [F; WIDTH], hash_state_cursor: &mut usize, - ) { + ) -> usize { + let mut nb_permutes = 0; let mut input_records = Vec::new(); let mut previous_state = *hash_state; let mut iter_num_consumed = 0; @@ -84,6 +83,7 @@ impl Poseidon2AbsorbEvent { // Do a permutation when the hash state is full. if *hash_state_cursor == RATE { + nb_permutes += 1; let perm_input = *hash_state; *hash_state = permuter.permute(*hash_state); @@ -106,6 +106,7 @@ impl Poseidon2AbsorbEvent { } if *hash_state_cursor != 0 { + nb_permutes += 1; // Note that we still do a permutation, generate the trace and enforce permutation // constraints for every absorb and finalize row. self.iterations.push(Poseidon2AbsorbIteration { @@ -119,6 +120,7 @@ impl Poseidon2AbsorbEvent { do_perm: false, }); } + nb_permutes } } diff --git a/recursion/core/src/poseidon2_wide/mod.rs b/crates/recursion/core/src/poseidon2_wide/mod.rs similarity index 54% rename from recursion/core/src/poseidon2_wide/mod.rs rename to crates/recursion/core/src/poseidon2_wide/mod.rs index f146593d97..e7e6f9cc11 100644 --- a/recursion/core/src/poseidon2_wide/mod.rs +++ b/crates/recursion/core/src/poseidon2_wide/mod.rs @@ -1,12 +1,12 @@ #![allow(clippy::needless_range_loop)] -use std::borrow::Borrow; -use std::borrow::BorrowMut; -use std::ops::Deref; +use std::{ + borrow::{Borrow, BorrowMut}, + ops::Deref, +}; use p3_baby_bear::{MONTY_INVERSE, POSEIDON2_INTERNAL_MATRIX_DIAG_16_BABYBEAR_MONTY}; -use p3_field::AbstractField; -use p3_field::PrimeField32; +use p3_field::{AbstractField, PrimeField32}; pub mod air; pub mod columns; @@ -15,10 +15,7 @@ pub mod trace; use p3_poseidon2::matmul_internal; -use self::columns::Poseidon2; -use self::columns::Poseidon2Degree3; -use self::columns::Poseidon2Degree9; -use self::columns::Poseidon2Mut; +use self::columns::{Poseidon2, Poseidon2Degree3, Poseidon2Degree9, Poseidon2Mut}; /// The width of the permutation. pub const WIDTH: usize = 16; @@ -89,12 +86,8 @@ pub(crate) fn external_linear_layer(state: &mut [AF; WIDTH]) for j in (0..WIDTH).step_by(4) { apply_m_4(&mut state[j..j + 4]); } - let sums: [AF; 4] = core::array::from_fn(|k| { - (0..WIDTH) - .step_by(4) - .map(|j| state[j + k].clone()) - .sum::() - }); + let sums: [AF; 4] = + core::array::from_fn(|k| (0..WIDTH).step_by(4).map(|j| state[j + k].clone()).sum::()); for j in 0..WIDTH { state[j] += sums[j % 4].clone(); @@ -116,13 +109,14 @@ pub(crate) fn internal_linear_layer(state: &mut [F; WIDTH]) { #[cfg(test)] pub(crate) mod tests { - use std::array; - use std::time::Instant; - - use crate::air::Block; - use crate::memory::MemoryRecord; - use crate::poseidon2_wide::events::Poseidon2HashEvent; - use crate::runtime::{ExecutionRecord, DIGEST_SIZE}; + use std::{array, time::Instant}; + + use crate::{ + air::Block, + memory::MemoryRecord, + poseidon2_wide::events::Poseidon2HashEvent, + runtime::{ExecutionRecord, DIGEST_SIZE}, + }; use itertools::Itertools; use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_field::AbstractField; @@ -130,21 +124,22 @@ pub(crate) mod tests { use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; use p3_symmetric::Permutation; use rand::random; - use sp1_core::air::MachineAir; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::utils::{inner_perm, uni_stark_prove, uni_stark_verify, BabyBearPoseidon2}; + + use sp1_core_machine::utils::{uni_stark_prove, uni_stark_verify}; + use sp1_stark::{ + air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, inner_perm, StarkGenericConfig, + }; use zkhash::ark_ff::UniformRand; - use super::events::{Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent}; - use super::{Poseidon2WideChip, WIDTH}; + use super::{ + events::{Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent}, + Poseidon2WideChip, WIDTH, + }; fn poseidon2_wide_prove_babybear_degree( input_exec: ExecutionRecord, ) { - let chip = Poseidon2WideChip:: { - fixed_log2_rows: None, - pad: true, - }; + let chip = Poseidon2WideChip:: { fixed_log2_rows: None, pad: true }; let trace: RowMajorMatrix = chip.generate_trace(&input_exec, &mut ExecutionRecord::::default()); @@ -197,116 +192,108 @@ pub(crate) mod tests { // Generate hash test events. let hash_test_input_sizes: [usize; NUM_ABSORBS] = array::from_fn(|_| random::() % 128 + 1); - hash_test_input_sizes - .iter() - .enumerate() - .for_each(|(i, input_size)| { - let test_input = (0..*input_size).map(|_| BabyBear::rand(rng)).collect_vec(); - - let prev_ts = BabyBear::from_canonical_usize(i); - let absorb_ts = BabyBear::from_canonical_usize(i + 1); - let finalize_ts = BabyBear::from_canonical_usize(i + 2); - let hash_num = i as u32; - let absorb_num = 0_u32; - let hash_and_absorb_num = - BabyBear::from_canonical_u32(hash_num * (1 << 12) + absorb_num); - let start_addr = BabyBear::from_canonical_usize(i + 1); - let input_len = BabyBear::from_canonical_usize(*input_size); - - let mut absorb_event = Poseidon2AbsorbEvent::new( - absorb_ts, - hash_and_absorb_num, - start_addr, - input_len, - BabyBear::from_canonical_u32(hash_num), - BabyBear::from_canonical_u32(absorb_num), - ); - - let mut hash_state = [BabyBear::zero(); WIDTH]; - let mut hash_state_cursor = 0; - absorb_event.populate_iterations( - start_addr, - input_len, - &dummy_memory_access_records(test_input.clone(), prev_ts, absorb_ts), - &permuter, - &mut hash_state, - &mut hash_state_cursor, - ); - - input_exec - .poseidon2_hash_events - .push(Poseidon2HashEvent::Absorb(absorb_event)); - - let do_perm = hash_state_cursor != 0; - let mut perm_output = permuter.permute(hash_state); - if incorrect_trace { - perm_output = [BabyBear::rand(rng); WIDTH]; - } - - let state = if do_perm { perm_output } else { hash_state }; - - input_exec - .poseidon2_hash_events - .push(Poseidon2HashEvent::Finalize(Poseidon2FinalizeEvent { - clk: finalize_ts, - hash_num: BabyBear::from_canonical_u32(hash_num), - output_ptr: start_addr, - output_records: dummy_memory_access_records( - state.as_slice().to_vec(), - absorb_ts, - finalize_ts, - )[0..DIGEST_SIZE] - .try_into() - .unwrap(), - state_cursor: hash_state_cursor, - perm_input: hash_state, - perm_output, - previous_state: hash_state, - state, - do_perm, - })); - }); + hash_test_input_sizes.iter().enumerate().for_each(|(i, input_size)| { + let test_input = (0..*input_size).map(|_| BabyBear::rand(rng)).collect_vec(); + + let prev_ts = BabyBear::from_canonical_usize(i); + let absorb_ts = BabyBear::from_canonical_usize(i + 1); + let finalize_ts = BabyBear::from_canonical_usize(i + 2); + let hash_num = i as u32; + let absorb_num = 0_u32; + let hash_and_absorb_num = + BabyBear::from_canonical_u32(hash_num * (1 << 12) + absorb_num); + let start_addr = BabyBear::from_canonical_usize(i + 1); + let input_len = BabyBear::from_canonical_usize(*input_size); + + let mut absorb_event = Poseidon2AbsorbEvent::new( + absorb_ts, + hash_and_absorb_num, + start_addr, + input_len, + BabyBear::from_canonical_u32(hash_num), + BabyBear::from_canonical_u32(absorb_num), + ); + + let mut hash_state = [BabyBear::zero(); WIDTH]; + let mut hash_state_cursor = 0; + absorb_event.populate_iterations( + start_addr, + input_len, + &dummy_memory_access_records(test_input.clone(), prev_ts, absorb_ts), + &permuter, + &mut hash_state, + &mut hash_state_cursor, + ); + + input_exec.poseidon2_hash_events.push(Poseidon2HashEvent::Absorb(absorb_event)); + + let do_perm = hash_state_cursor != 0; + let mut perm_output = permuter.permute(hash_state); + if incorrect_trace { + perm_output = [BabyBear::rand(rng); WIDTH]; + } + + let state = if do_perm { perm_output } else { hash_state }; + + input_exec.poseidon2_hash_events.push(Poseidon2HashEvent::Finalize( + Poseidon2FinalizeEvent { + clk: finalize_ts, + hash_num: BabyBear::from_canonical_u32(hash_num), + output_ptr: start_addr, + output_records: dummy_memory_access_records( + state.as_slice().to_vec(), + absorb_ts, + finalize_ts, + )[0..DIGEST_SIZE] + .try_into() + .unwrap(), + state_cursor: hash_state_cursor, + perm_input: hash_state, + perm_output, + previous_state: hash_state, + state, + do_perm, + }, + )); + }); let compress_test_inputs: Vec<[BabyBear; WIDTH]> = (0..NUM_COMPRESSES) .map(|_| core::array::from_fn(|_| BabyBear::rand(rng))) .collect_vec(); - compress_test_inputs - .iter() - .enumerate() - .for_each(|(i, input)| { - let mut result_array = permuter.permute(*input); - if incorrect_trace { - result_array = core::array::from_fn(|_| BabyBear::rand(rng)); - } - let prev_ts = BabyBear::from_canonical_usize(i); - let input_ts = BabyBear::from_canonical_usize(i + 1); - let output_ts = BabyBear::from_canonical_usize(i + 2); - - let dst = BabyBear::from_canonical_usize(i + 1); - let left = dst + BabyBear::from_canonical_usize(WIDTH / 2); - let right = left + BabyBear::from_canonical_usize(WIDTH / 2); - - let compress_event = Poseidon2CompressEvent { - clk: input_ts, - dst, - left, - right, - input: *input, - result_array, - input_records: dummy_memory_access_records(input.to_vec(), prev_ts, input_ts) - .try_into() - .unwrap(), - result_records: dummy_memory_access_records( - result_array.to_vec(), - input_ts, - output_ts, - ) + compress_test_inputs.iter().enumerate().for_each(|(i, input)| { + let mut result_array = permuter.permute(*input); + if incorrect_trace { + result_array = core::array::from_fn(|_| BabyBear::rand(rng)); + } + let prev_ts = BabyBear::from_canonical_usize(i); + let input_ts = BabyBear::from_canonical_usize(i + 1); + let output_ts = BabyBear::from_canonical_usize(i + 2); + + let dst = BabyBear::from_canonical_usize(i + 1); + let left = dst + BabyBear::from_canonical_usize(WIDTH / 2); + let right = left + BabyBear::from_canonical_usize(WIDTH / 2); + + let compress_event = Poseidon2CompressEvent { + clk: input_ts, + dst, + left, + right, + input: *input, + result_array, + input_records: dummy_memory_access_records(input.to_vec(), prev_ts, input_ts) .try_into() .unwrap(), - }; - - input_exec.poseidon2_compress_events.push(compress_event); - }); + result_records: dummy_memory_access_records( + result_array.to_vec(), + input_ts, + output_ts, + ) + .try_into() + .unwrap(), + }; + + input_exec.poseidon2_compress_events.push(compress_event); + }); input_exec } diff --git a/recursion/core/src/poseidon2_wide/trace.rs b/crates/recursion/core/src/poseidon2_wide/trace.rs similarity index 89% rename from recursion/core/src/poseidon2_wide/trace.rs rename to crates/recursion/core/src/poseidon2_wide/trace.rs index 3f4612045b..db4fa9b3dd 100644 --- a/recursion/core/src/poseidon2_wide/trace.rs +++ b/crates/recursion/core/src/poseidon2_wide/trace.rs @@ -3,26 +3,25 @@ use std::borrow::Borrow; use p3_air::BaseAir; use p3_field::PrimeField32; use p3_matrix::dense::RowMajorMatrix; -use p3_maybe_rayon::prelude::IndexedParallelIterator; -use p3_maybe_rayon::prelude::ParallelIterator; -use p3_maybe_rayon::prelude::ParallelSliceMut; -use sp1_core::air::MachineAir; -use sp1_core::utils::next_power_of_two; -use sp1_core::utils::par_for_each_row; +use p3_maybe_rayon::prelude::{IndexedParallelIterator, ParallelIterator, ParallelSliceMut}; +use sp1_core_machine::utils::{next_power_of_two, par_for_each_row}; use sp1_primitives::RC_16_30_U32; +use sp1_stark::air::MachineAir; use tracing::instrument; -use crate::poseidon2_wide::columns::permutation::permutation_mut; -use crate::poseidon2_wide::events::Poseidon2HashEvent; -use crate::range_check::{RangeCheckEvent, RangeCheckOpcode}; use crate::{ - poseidon2_wide::{external_linear_layer, NUM_EXTERNAL_ROUNDS, WIDTH}, + poseidon2_wide::{ + columns::permutation::permutation_mut, events::Poseidon2HashEvent, external_linear_layer, + NUM_EXTERNAL_ROUNDS, WIDTH, + }, + range_check::{RangeCheckEvent, RangeCheckOpcode}, runtime::{ExecutionRecord, RecursionProgram}, }; -use super::events::{Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent}; -use super::RATE; -use super::{internal_linear_layer, Poseidon2WideChip, NUM_INTERNAL_ROUNDS}; +use super::{ + events::{Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent}, + internal_linear_layer, Poseidon2WideChip, NUM_INTERNAL_ROUNDS, RATE, +}; impl MachineAir for Poseidon2WideChip { type Record = ExecutionRecord; @@ -53,17 +52,15 @@ impl MachineAir for Poseidon2WideChip as BaseAir>::width(self); let mut rows = vec![F::zero(); nb_padded_rows * num_columns]; - // Populate the hash events. We do this serially, since each absorb event could populate a different - // number of rows. Also, most of the rows are populated by the compress events. + // Populate the hash events. We do this serially, since each absorb event could populate a + // different number of rows. Also, most of the rows are populated by the compress + // events. let mut row_cursor = 0; for event in &input.poseidon2_hash_events { match event { @@ -222,7 +219,8 @@ impl Poseidon2WideChip { num_columns: usize, output: &mut ExecutionRecord, ) { - // We currently don't support an input_len of 0, since it will need special logic in the AIR. + // We currently don't support an input_len of 0, since it will need special logic in the + // AIR. assert!(absorb_event.input_len > F::zero()); let mut last_row_ending_cursor = 0; @@ -297,9 +295,10 @@ impl Poseidon2WideChip { )]); // Calculate last_row_num_consumed. - // For absorb calls that span multiple rows (e.g. the last row is not the syscall row), - // last_row_num_consumed = (input_len + state_cursor) % 8 at the syscall row. - // For absorb calls that are only one row, last_row_num_consumed = absorb_event.input_len. + // For absorb calls that span multiple rows (e.g. the last row is not the syscall + // row), last_row_num_consumed = (input_len + state_cursor) % 8 at + // the syscall row. For absorb calls that are only one row, + // last_row_num_consumed = absorb_event.input_len. if is_syscall_row { last_row_ending_cursor = (absorb_iter.state_cursor + absorb_event.input_len.as_canonical_u32() as usize @@ -310,21 +309,16 @@ impl Poseidon2WideChip { absorb_workspace.last_row_ending_cursor = F::from_canonical_usize(last_row_ending_cursor); - absorb_workspace - .last_row_ending_cursor_is_seven - .populate_from_field_element( - F::from_canonical_usize(last_row_ending_cursor) - - F::from_canonical_usize(7), - ); + absorb_workspace.last_row_ending_cursor_is_seven.populate_from_field_element( + F::from_canonical_usize(last_row_ending_cursor) - F::from_canonical_usize(7), + ); (0..3).for_each(|i| { absorb_workspace.last_row_ending_cursor_bitmap[i] = F::from_bool((last_row_ending_cursor) & (1 << i) == (1 << i)) }); - absorb_workspace - .num_remaining_rows_is_zero - .populate(num_remaining_rows as u32); + absorb_workspace.num_remaining_rows_is_zero.populate(num_remaining_rows as u32); absorb_workspace.is_syscall_not_last_row = F::from_bool(is_syscall_row && !is_last_row); @@ -356,11 +350,7 @@ impl Poseidon2WideChip { // Populate the permutation fields. self.populate_permutation( absorb_iter.perm_input, - if absorb_iter.do_perm { - Some(absorb_iter.perm_output) - } else { - None - }, + if absorb_iter.do_perm { Some(absorb_iter.perm_output) } else { None }, absorb_row, ); } @@ -409,19 +399,13 @@ impl Poseidon2WideChip { finalize_workspace.previous_state = finalize_event.previous_state; finalize_workspace.state = finalize_event.state; finalize_workspace.state_cursor = F::from_canonical_usize(finalize_event.state_cursor); - finalize_workspace - .state_cursor_is_zero - .populate(finalize_event.state_cursor as u32); + finalize_workspace.state_cursor_is_zero.populate(finalize_event.state_cursor as u32); } // Populate the permutation fields. self.populate_permutation( finalize_event.perm_input, - if finalize_event.do_perm { - Some(finalize_event.perm_output) - } else { - None - }, + if finalize_event.do_perm { Some(finalize_event.perm_output) } else { None }, row, ); } @@ -493,12 +477,9 @@ impl Poseidon2WideChip { // Add round constants. // // Optimization: Since adding a constant is a degree 1 operation, we can avoid adding - // columns for it, and instead include it in the constraint for the x^3 part of the sbox. - let round = if r < NUM_EXTERNAL_ROUNDS / 2 { - r - } else { - r + NUM_INTERNAL_ROUNDS - }; + // columns for it, and instead include it in the constraint for the x^3 part of the + // sbox. + let round = if r < NUM_EXTERNAL_ROUNDS / 2 { r } else { r + NUM_INTERNAL_ROUNDS }; let mut add_rc = *round_state; for i in 0..WIDTH { add_rc[i] += F::from_wrapped_u32(RC_16_30_U32[round][i]); diff --git a/recursion/core/src/program/mod.rs b/crates/recursion/core/src/program/mod.rs similarity index 81% rename from recursion/core/src/program/mod.rs rename to crates/recursion/core/src/program/mod.rs index c8745378a2..81a2fc2a41 100644 --- a/recursion/core/src/program/mod.rs +++ b/crates/recursion/core/src/program/mod.rs @@ -1,20 +1,22 @@ use crate::air::SP1RecursionAirBuilder; -use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; use p3_air::{Air, BaseAir, PairBuilder}; use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use sp1_core::air::MachineAir; -use sp1_core::utils::pad_rows_fixed; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use sp1_core_machine::utils::pad_rows_fixed; +use sp1_stark::air::MachineAir; use std::collections::HashMap; use tracing::instrument; use sp1_derive::AlignedBorrow; -use crate::cpu::columns::InstructionCols; -use crate::cpu::columns::OpcodeSelectorCols; -use crate::runtime::{ExecutionRecord, RecursionProgram}; +use crate::{ + cpu::columns::{InstructionCols, OpcodeSelectorCols}, + runtime::{ExecutionRecord, RecursionProgram}, +}; pub const NUM_PROGRAM_PREPROCESSED_COLS: usize = size_of::>(); pub const NUM_PROGRAM_MULT_COLS: usize = size_of::>(); @@ -59,10 +61,7 @@ impl MachineAir for ProgramChip { } fn generate_preprocessed_trace(&self, program: &Self::Program) -> Option> { - let max_program_size = match std::env::var("MAX_RECURSION_PROGRAM_SIZE") { - Ok(value) => value.parse().unwrap(), - Err(_) => std::cmp::min(1048576, program.instructions.len()), - }; + let max_program_size = program.instructions.len(); let mut rows = program.instructions[0..max_program_size] .iter() .enumerate() @@ -78,11 +77,7 @@ impl MachineAir for ProgramChip { .collect::>(); // Pad the trace to a power of two. - pad_rows_fixed( - &mut rows, - || [F::zero(); NUM_PROGRAM_PREPROCESSED_COLS], - None, - ); + pad_rows_fixed(&mut rows, || [F::zero(); NUM_PROGRAM_PREPROCESSED_COLS], None); // Convert the trace to a row major matrix. Some(RowMajorMatrix::new( @@ -112,10 +107,7 @@ impl MachineAir for ProgramChip { .or_insert(1); }); - let max_program_size = match std::env::var("MAX_RECURSION_PROGRAM_SIZE") { - Ok(value) => value.parse().unwrap(), - Err(_) => std::cmp::min(1048576, input.program.instructions.len()), - }; + let max_program_size = input.program.instructions.len(); let mut rows = input.program.instructions[0..max_program_size] .iter() .enumerate() @@ -133,10 +125,7 @@ impl MachineAir for ProgramChip { pad_rows_fixed(&mut rows, || [F::zero(); NUM_PROGRAM_MULT_COLS], None); // Convert the trace to a row major matrix. - RowMajorMatrix::new( - rows.into_iter().flatten().collect::>(), - NUM_PROGRAM_MULT_COLS, - ) + RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_PROGRAM_MULT_COLS) } fn included(&self, _: &Self::Record) -> bool { diff --git a/recursion/core/src/range_check/air.rs b/crates/recursion/core/src/range_check/air.rs similarity index 85% rename from recursion/core/src/range_check/air.rs rename to crates/recursion/core/src/range_check/air.rs index 3e64b76800..0845c3c78d 100644 --- a/recursion/core/src/range_check/air.rs +++ b/crates/recursion/core/src/range_check/air.rs @@ -1,12 +1,13 @@ use core::borrow::Borrow; -use p3_air::PairBuilder; -use p3_air::{Air, AirBuilder, BaseAir}; +use p3_air::{Air, AirBuilder, BaseAir, PairBuilder}; use p3_field::Field; use p3_matrix::Matrix; -use super::columns::{RangeCheckMultCols, RangeCheckPreprocessedCols, NUM_RANGE_CHECK_MULT_COLS}; -use super::{RangeCheckChip, RangeCheckOpcode}; +use super::{ + columns::{RangeCheckMultCols, RangeCheckPreprocessedCols, NUM_RANGE_CHECK_MULT_COLS}, + RangeCheckChip, RangeCheckOpcode, +}; use crate::air::SP1RecursionAirBuilder; impl BaseAir for RangeCheckChip { diff --git a/recursion/core/src/range_check/columns.rs b/crates/recursion/core/src/range_check/columns.rs similarity index 91% rename from recursion/core/src/range_check/columns.rs rename to crates/recursion/core/src/range_check/columns.rs index 9fe8f07e53..eef8421394 100644 --- a/recursion/core/src/range_check/columns.rs +++ b/crates/recursion/core/src/range_check/columns.rs @@ -19,8 +19,8 @@ pub struct RangeCheckPreprocessedCols { pub u12_out_range: T, } -/// For each byte operation in the preprocessed table, a corresponding RangeCheckMultCols row tracks the -/// number of times the operation is used. +/// For each byte operation in the preprocessed table, a corresponding RangeCheckMultCols row tracks +/// the number of times the operation is used. #[derive(Debug, Clone, Copy, AlignedBorrow)] #[repr(C)] pub struct RangeCheckMultCols { diff --git a/recursion/core/src/range_check/event.rs b/crates/recursion/core/src/range_check/event.rs similarity index 100% rename from recursion/core/src/range_check/event.rs rename to crates/recursion/core/src/range_check/event.rs diff --git a/recursion/core/src/range_check/mod.rs b/crates/recursion/core/src/range_check/mod.rs similarity index 94% rename from recursion/core/src/range_check/mod.rs rename to crates/recursion/core/src/range_check/mod.rs index c3fc318ec3..f94ccbdc10 100644 --- a/recursion/core/src/range_check/mod.rs +++ b/crates/recursion/core/src/range_check/mod.rs @@ -22,8 +22,8 @@ pub const NUM_RANGE_CHECK_OPS: usize = 2; /// A chip for computing range check operations. /// -/// The chip contains a preprocessed table of all possible range check operations. Other chips can then -/// use lookups into this table to range check their values. +/// The chip contains a preprocessed table of all possible range check operations. Other chips can +/// then use lookups into this table to range check their values. #[derive(Debug, Clone, Copy, Default)] pub struct RangeCheckChip(PhantomData); @@ -32,7 +32,8 @@ impl RangeCheckChip { /// /// This function returns a pair `(trace, map)`, where: /// - `trace` is a matrix containing all possible range check values. - /// - `map` is a map from a range check lookup to the value's corresponding row it appears in the table and + /// - `map` is a map from a range check lookup to the value's corresponding row it appears in + /// the table and /// the index of the result in the array of multiplicities. pub fn trace_and_map() -> (RowMajorMatrix, BTreeMap) { // A map from a byte lookup to its corresponding row in the table and index in the array of diff --git a/recursion/core/src/range_check/opcode.rs b/crates/recursion/core/src/range_check/opcode.rs similarity index 100% rename from recursion/core/src/range_check/opcode.rs rename to crates/recursion/core/src/range_check/opcode.rs diff --git a/recursion/core/src/range_check/trace.rs b/crates/recursion/core/src/range_check/trace.rs similarity index 98% rename from recursion/core/src/range_check/trace.rs rename to crates/recursion/core/src/range_check/trace.rs index ae3248a385..ca77a0c8b2 100644 --- a/recursion/core/src/range_check/trace.rs +++ b/crates/recursion/core/src/range_check/trace.rs @@ -2,7 +2,7 @@ use std::borrow::BorrowMut; use p3_field::PrimeField32; use p3_matrix::dense::RowMajorMatrix; -use sp1_core::air::MachineAir; +use sp1_stark::air::MachineAir; use super::{ columns::{RangeCheckMultCols, NUM_RANGE_CHECK_MULT_COLS, NUM_RANGE_CHECK_PREPROCESSED_COLS}, diff --git a/recursion/core/src/runtime/instruction.rs b/crates/recursion/core/src/runtime/instruction.rs similarity index 100% rename from recursion/core/src/runtime/instruction.rs rename to crates/recursion/core/src/runtime/instruction.rs diff --git a/recursion/core/src/runtime/mod.rs b/crates/recursion/core/src/runtime/mod.rs similarity index 90% rename from recursion/core/src/runtime/mod.rs rename to crates/recursion/core/src/runtime/mod.rs index 57ee7bc3e0..045a6557be 100644 --- a/recursion/core/src/runtime/mod.rs +++ b/crates/recursion/core/src/runtime/mod.rs @@ -4,34 +4,32 @@ mod program; mod record; mod utils; -use std::collections::VecDeque; -use std::{array, fmt}; -use std::{marker::PhantomData, sync::Arc}; +use std::{array, collections::VecDeque, fmt, marker::PhantomData, sync::Arc}; use hashbrown::HashMap; pub use instruction::*; use itertools::Itertools; pub use opcode::*; -use p3_poseidon2::Poseidon2; -use p3_poseidon2::Poseidon2ExternalMatrixGeneral; -use p3_symmetric::CryptographicPermutation; -use p3_symmetric::Permutation; +use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +use p3_symmetric::{CryptographicPermutation, Permutation}; pub use program::*; pub use record::*; +use sp1_core_executor::events::MemoryAccessPosition; pub use utils::*; -use crate::air::{Block, RECURSION_PUBLIC_VALUES_COL_MAP, RECURSIVE_PROOF_NUM_PV_ELTS}; -use crate::cpu::CpuEvent; -use crate::exp_reverse_bits::ExpReverseBitsLenEvent; -use crate::fri_fold::FriFoldEvent; -use crate::memory::{compute_addr_diff, MemoryRecord}; -use crate::poseidon2_wide::events::{ - Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent, Poseidon2HashEvent, +use crate::{ + air::{Block, RECURSION_PUBLIC_VALUES_COL_MAP, RECURSIVE_PROOF_NUM_PV_ELTS}, + cpu::CpuEvent, + exp_reverse_bits::ExpReverseBitsLenEvent, + fri_fold::FriFoldEvent, + memory::{compute_addr_diff, MemoryRecord}, + poseidon2_wide::events::{ + Poseidon2AbsorbEvent, Poseidon2CompressEvent, Poseidon2FinalizeEvent, Poseidon2HashEvent, + }, + range_check::{RangeCheckEvent, RangeCheckOpcode}, }; -use crate::range_check::{RangeCheckEvent, RangeCheckOpcode}; use p3_field::{ExtensionField, PrimeField32}; -use sp1_core::runtime::MemoryAccessPosition; /// The heap pointer address. pub const HEAP_PTR: i32 = -4; @@ -45,7 +43,8 @@ pub const PERMUTATION_WIDTH: usize = 16; pub const POSEIDON2_SBOX_DEGREE: u64 = 7; pub const HASH_RATE: usize = 8; -/// The current verifier implementation assumes that we are using a 256-bit hash with 32-bit elements. +/// The current verifier implementation assumes that we are using a 256-bit hash with 32-bit +/// elements. pub const DIGEST_SIZE: usize = 8; pub const NUM_BITS: usize = 31; @@ -78,6 +77,12 @@ pub struct Runtime, Diffusion> { pub nb_poseidons: usize, + pub nb_poseidon_permutes: usize, + + pub nb_erb_lens: usize, + + pub nb_fri_folds: usize, + pub nb_bit_decompositions: usize, pub nb_ext_ops: usize, @@ -177,13 +182,14 @@ where POSEIDON2_SBOX_DEGREE, >, ) -> Self { - let record = ExecutionRecord:: { - program: Arc::new(program.clone()), - ..Default::default() - }; + let record = + ExecutionRecord:: { program: Arc::new(program.clone()), ..Default::default() }; Self { timestamp: 0, nb_poseidons: 0, + nb_poseidon_permutes: 0, + nb_erb_lens: 0, + nb_fri_folds: 0, nb_bit_decompositions: 0, nb_ext_ops: 0, nb_base_ops: 0, @@ -210,13 +216,14 @@ where } pub fn new_no_perm(program: &RecursionProgram) -> Self { - let record = ExecutionRecord:: { - program: Arc::new(program.clone()), - ..Default::default() - }; + let record = + ExecutionRecord:: { program: Arc::new(program.clone()), ..Default::default() }; Self { timestamp: 0, nb_poseidons: 0, + nb_poseidon_permutes: 0, + nb_erb_lens: 0, + nb_fri_folds: 0, nb_bit_decompositions: 0, nb_ext_ops: 0, nb_base_ops: 0, @@ -245,6 +252,9 @@ where pub fn print_stats(&self) { tracing::debug!("Total Cycles: {}", self.timestamp); tracing::debug!("Poseidon Operations: {}", self.nb_poseidons); + tracing::debug!("Poseidon Permute Operations: {}", self.nb_poseidon_permutes); + tracing::debug!("Exp Reverse Bits Len Operations: {}", self.nb_erb_lens); + tracing::debug!("FRI Fold Operations: {}", self.nb_fri_folds); tracing::debug!("Field Operations: {}", self.nb_base_ops); tracing::debug!("Extension Operations: {}", self.nb_ext_ops); tracing::debug!("Memory Operations: {}", self.nb_memory_ops); @@ -256,13 +266,7 @@ where // Peek at the memory without touching the record. fn peek(&mut self, addr: F) -> (F, Block) { - ( - addr, - self.memory - .get(&(addr.as_canonical_u32() as usize)) - .unwrap() - .value, - ) + (addr, self.memory.get(&(addr.as_canonical_u32() as usize)).unwrap().value) } // Write to uninitialized memory. @@ -276,10 +280,7 @@ where self.memory .entry(addr) .and_modify(|_| panic!("address already initialized")) - .or_insert(MemoryEntry { - value, - timestamp: F::zero(), - }); + .or_insert(MemoryEntry { value, timestamp: F::zero() }); } /// Given a MemoryRecord event, track the range checks for the memory access. @@ -293,8 +294,7 @@ where RangeCheckOpcode::U12, record.diff_12bit_limb.as_canonical_u32() as u16, ); - self.record - .add_range_check_events(&[diff_16bit_limb_event, diff_12bit_limb_event]); + self.record.add_range_check_events(&[diff_16bit_limb_event, diff_12bit_limb_event]); } /// Track the range checks for the memory finalize table. This will be used later to set the @@ -307,21 +307,14 @@ where RangeCheckEvent::new(RangeCheckOpcode::U16, diff_16.as_canonical_u32() as u16); let diff_8bit_limb_event = RangeCheckEvent::new(RangeCheckOpcode::U12, diff_12.as_canonical_u32() as u16); - self.record - .add_range_check_events(&[diff_16bit_limb_event, diff_8bit_limb_event]); + self.record.add_range_check_events(&[diff_16bit_limb_event, diff_8bit_limb_event]); } fn mr(&mut self, addr: F, timestamp: F) -> (MemoryRecord, Block) { - let entry = self - .memory - .entry(addr.as_canonical_u32() as usize) - .or_default(); + let entry = self.memory.entry(addr.as_canonical_u32() as usize).or_default(); let (prev_value, prev_timestamp) = (entry.value, entry.timestamp); let record = MemoryRecord::new_read(addr, prev_value, timestamp, prev_timestamp); - *entry = MemoryEntry { - value: prev_value, - timestamp, - }; + *entry = MemoryEntry { value: prev_value, timestamp }; self.track_memory_range_checks(&record); (record, prev_value) } @@ -345,10 +338,7 @@ where let value_as_block = value.into(); let record = MemoryRecord::new_write(addr, value_as_block, timestamp, prev_value, prev_timestamp); - *entry = MemoryEntry { - value: value_as_block, - timestamp, - }; + *entry = MemoryEntry { value: value_as_block, timestamp }; self.track_memory_range_checks(&record); record } @@ -496,8 +486,7 @@ where if instruction_is_heap_expand(&instruction) { let (u16_range_check, u12_range_check) = get_heap_size_range_check_events(a_val[0]); - self.record - .add_range_check_events(&[u16_range_check, u12_range_check]); + self.record.add_range_check_events(&[u16_range_check, u12_range_check]); } (a, b, c) = (a_val, b_val, c_val); @@ -627,9 +616,7 @@ where (a, b, c) = (a_val, b_val, c_val); } Opcode::TRAP => { - self.record - .public_values - .resize(RECURSIVE_PROOF_NUM_PV_ELTS, F::zero()); + self.record.public_values.resize(RECURSIVE_PROOF_NUM_PV_ELTS, F::zero()); self.record.public_values[RECURSION_PUBLIC_VALUES_COL_MAP.exit_code] = F::one(); let trap_pc = self.pc.as_canonical_u32() as usize; @@ -652,9 +639,7 @@ where } } Opcode::HALT => { - self.record - .public_values - .resize(RECURSIVE_PROOF_NUM_PV_ELTS, F::zero()); + self.record.public_values.resize(RECURSIVE_PROOF_NUM_PV_ELTS, F::zero()); self.record.public_values[RECURSION_PUBLIC_VALUES_COL_MAP.exit_code] = F::zero(); @@ -672,6 +657,7 @@ where } Opcode::Poseidon2Compress => { self.nb_poseidons += 1; + self.nb_poseidon_permutes += 1; let (a_val, b_val, c_val) = self.all_rr(&instruction); @@ -717,18 +703,16 @@ where )); } - self.record - .poseidon2_compress_events - .push(Poseidon2CompressEvent { - clk: timestamp, - dst, - left, - right, - input: array, - result_array: result, - input_records, - result_records: result_records.try_into().unwrap(), - }); + self.record.poseidon2_compress_events.push(Poseidon2CompressEvent { + clk: timestamp, + dst, + left, + right, + input: array, + result_array: result, + input_records, + result_records: result_records.try_into().unwrap(), + }); (a, b, c) = (a_val, b_val, c_val); } @@ -748,12 +732,13 @@ where let hash_num = F::from_canonical_u32(hash_and_absorb_num_u32 / two_pow_12); let absorb_num = F::from_canonical_u32(hash_and_absorb_num_u32 % two_pow_12); - // Double check that hash_num is [0, 2^16 - 1] and absorb_num is [0, 2^12 - 1] since - // that is what the AIR will enforce. + // Double check that hash_num is [0, 2^16 - 1] and absorb_num is [0, 2^12 - 1] + // since that is what the AIR will enforce. assert!(hash_num.as_canonical_u32() < 1 << 16); assert!(absorb_num.as_canonical_u32() < 1 << 12); - // We currently don't support an input_len of 0, since it will need special logic in the AIR. + // We currently don't support an input_len of 0, since it will need special + // logic in the AIR. assert!(input_len > F::zero()); let mut absorb_event = Poseidon2AbsorbEvent::new( @@ -770,7 +755,7 @@ where .collect_vec(); let permuter = self.perm.as_ref().unwrap().clone(); - absorb_event.populate_iterations( + self.nb_poseidon_permutes += absorb_event.populate_iterations( start_addr, input_len, &memory_records, @@ -800,6 +785,7 @@ where let do_perm = self.p2_hash_state_cursor != 0; let perm_output = self.perm.as_ref().unwrap().permute(self.p2_hash_state); let state = if do_perm { + self.nb_poseidon_permutes += 1; perm_output } else { self.p2_hash_state @@ -808,9 +794,8 @@ where self.mw(output_ptr + F::from_canonical_usize(i), state[i], timestamp) }); - self.record - .poseidon2_hash_events - .push(Poseidon2HashEvent::Finalize(Poseidon2FinalizeEvent { + self.record.poseidon2_hash_events.push(Poseidon2HashEvent::Finalize( + Poseidon2FinalizeEvent { clk: timestamp, hash_num: p2_hash_num, output_ptr, @@ -821,7 +806,8 @@ where previous_state: self.p2_hash_state, state, do_perm, - })); + }, + )); self.p2_hash_state_cursor = 0; self.p2_hash_state = [F::zero(); PERMUTATION_WIDTH]; @@ -864,13 +850,15 @@ where Opcode::FRIFold => { let (a_val, b_val, c_val) = self.all_rr(&instruction); - // The timestamp for the memory reads for all of these operations will be self.clk + // The timestamp for the memory reads for all of these operations will be + // self.clk let ps_at_z_len = a_val[0]; let input_ptr = b_val[0]; let mut timestamp = self.clk; + self.nb_fri_folds += ps_at_z_len.as_canonical_u32() as usize; // Read the input values. for m in 0..ps_at_z_len.as_canonical_u32() { let m = F::from_canonical_u32(m); @@ -983,6 +971,7 @@ where let mut x_record = self.mr(base, timestamp).0; // Iterate over the `len` least-significant bits of the exponent. + self.nb_erb_lens += len.as_canonical_u32() as usize; for m in 0..len.as_canonical_u32() { let m = F::from_canonical_u32(m); @@ -999,11 +988,7 @@ where let prev_accum = accum; accum = prev_accum * prev_accum - * if current_bit == F::one() { - current_x_val - } else { - F::one() - }; + * if current_bit == F::one() { current_x_val } else { F::one() }; // On the last iteration, write accum to the address pointed to in `base`. if m == len - F::one() { @@ -1011,19 +996,17 @@ where }; // Add the event for this iteration to the `ExecutionRecord`. - self.record - .exp_reverse_bits_len_events - .push(ExpReverseBitsLenEvent { - clk: timestamp, - x: x_record, - current_bit: current_bit_record, - len: len - m, - prev_accum, - accum, - ptr, - base_ptr: base, - iteration_num: m, - }); + self.record.exp_reverse_bits_len_events.push(ExpReverseBitsLenEvent { + clk: timestamp, + x: x_record, + current_bit: current_bit_record, + len: len - m, + prev_accum, + accum, + ptr, + base_ptr: base, + iteration_num: m, + }); timestamp += F::one(); } @@ -1072,9 +1055,7 @@ where // Get the initial value of the memory address from either the uninitialized memory // or set it as a default to 0. let init_value = self.uninitialized_memory.get(addr).unwrap_or(&zero_block); - self.record - .first_memory_record - .push((F::from_canonical_usize(*addr), *init_value)); + self.record.first_memory_record.push((F::from_canonical_usize(*addr), *init_value)); self.record.last_memory_record.push(( F::from_canonical_usize(*addr), @@ -1082,13 +1063,11 @@ where entry.value, )) } - self.record - .last_memory_record - .sort_by_key(|(addr, _, _)| *addr); + self.record.last_memory_record.sort_by_key(|(addr, _, _)| *addr); // For all the records but the last, need to check that the next address is greater than the - // current address, and that the difference is bounded by 2^28. We also track that the current - // address is bounded by 2^28. + // current address, and that the difference is bounded by 2^28. We also track that the + // current address is bounded by 2^28. for i in 0..self.record.last_memory_record.len() - 1 { self.track_addr_range_check( self.record.last_memory_record[i].0, @@ -1111,10 +1090,8 @@ where #[cfg(test)] mod tests { use p3_field::AbstractField; - use sp1_core::{ - stark::{RiscvAir, StarkGenericConfig}, - utils::BabyBearPoseidon2, - }; + use sp1_core_machine::riscv::RiscvAir; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use super::{Instruction, Opcode, RecursionProgram, Runtime, RuntimeError}; @@ -1186,10 +1163,7 @@ mod tests { Runtime::::new(&trap_program, machine.config().perm.clone()); let trap_result = trap_runtime.run(); - assert!( - trap_result.is_err(), - "Expected run to return an error due to TRAP instruction" - ); + assert!(trap_result.is_err(), "Expected run to return an error due to TRAP instruction"); if let Err(RuntimeError::Trap(msg)) = trap_result { println!("Caught expected trap error: {}", msg); diff --git a/recursion/core/src/runtime/opcode.rs b/crates/recursion/core/src/runtime/opcode.rs similarity index 100% rename from recursion/core/src/runtime/opcode.rs rename to crates/recursion/core/src/runtime/opcode.rs diff --git a/recursion/core/src/runtime/program.rs b/crates/recursion/core/src/runtime/program.rs similarity index 92% rename from recursion/core/src/runtime/program.rs rename to crates/recursion/core/src/runtime/program.rs index 01006dc2dd..5ac33dafc8 100644 --- a/recursion/core/src/runtime/program.rs +++ b/crates/recursion/core/src/runtime/program.rs @@ -2,7 +2,7 @@ use super::Instruction; use backtrace::Backtrace; use p3_field::Field; use serde::{Deserialize, Serialize}; -use sp1_core::air::MachineProgram; +use sp1_stark::air::MachineProgram; #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct RecursionProgram { diff --git a/recursion/core/src/runtime/record.rs b/crates/recursion/core/src/runtime/record.rs similarity index 67% rename from recursion/core/src/runtime/record.rs rename to crates/recursion/core/src/runtime/record.rs index 5e2babb949..17cc25e318 100644 --- a/recursion/core/src/runtime/record.rs +++ b/crates/recursion/core/src/runtime/record.rs @@ -1,18 +1,18 @@ use hashbrown::HashMap; -use sp1_core::utils::SP1CoreOpts; -use std::array; -use std::sync::Arc; +use std::{array, sync::Arc}; use p3_field::{AbstractField, PrimeField32}; -use sp1_core::stark::{MachineRecord, PROOF_MAX_NUM_PVS}; +use sp1_stark::{MachineRecord, SP1CoreOpts, PROOF_MAX_NUM_PVS}; use super::RecursionProgram; -use crate::air::Block; -use crate::cpu::CpuEvent; -use crate::exp_reverse_bits::ExpReverseBitsLenEvent; -use crate::fri_fold::FriFoldEvent; -use crate::poseidon2_wide::events::{Poseidon2CompressEvent, Poseidon2HashEvent}; -use crate::range_check::RangeCheckEvent; +use crate::{ + air::Block, + cpu::CpuEvent, + exp_reverse_bits::ExpReverseBitsLenEvent, + fri_fold::FriFoldEvent, + poseidon2_wide::events::{Poseidon2CompressEvent, Poseidon2HashEvent}, + range_check::RangeCheckEvent, +}; #[derive(Default, Debug, Clone)] pub struct ExecutionRecord { @@ -47,19 +47,10 @@ impl MachineRecord for ExecutionRecord { fn stats(&self) -> HashMap { let mut stats = HashMap::new(); stats.insert("cpu_events".to_string(), self.cpu_events.len()); - stats.insert( - "poseidon2_events".to_string(), - self.poseidon2_compress_events.len(), - ); - stats.insert( - "poseidon2_events".to_string(), - self.poseidon2_hash_events.len(), - ); + stats.insert("poseidon2_events".to_string(), self.poseidon2_compress_events.len()); + stats.insert("poseidon2_events".to_string(), self.poseidon2_hash_events.len()); stats.insert("fri_fold_events".to_string(), self.fri_fold_events.len()); - stats.insert( - "range_check_events".to_string(), - self.range_check_events.len(), - ); + stats.insert("range_check_events".to_string(), self.range_check_events.len()); stats.insert( "exp_reverse_bits_len_events".to_string(), self.exp_reverse_bits_len_events.len(), @@ -70,18 +61,13 @@ impl MachineRecord for ExecutionRecord { // NOTE: This should be unused. fn append(&mut self, other: &mut Self) { self.cpu_events.append(&mut other.cpu_events); - self.first_memory_record - .append(&mut other.first_memory_record); - self.last_memory_record - .append(&mut other.last_memory_record); + self.first_memory_record.append(&mut other.first_memory_record); + self.last_memory_record.append(&mut other.last_memory_record); // Merge the range check lookups. for (range_check_event, count) in std::mem::take(&mut other.range_check_events).into_iter() { - *self - .range_check_events - .entry(range_check_event) - .or_insert(0) += count; + *self.range_check_events.entry(range_check_event).or_insert(0) += count; } } diff --git a/recursion/core/src/runtime/utils.rs b/crates/recursion/core/src/runtime/utils.rs similarity index 100% rename from recursion/core/src/runtime/utils.rs rename to crates/recursion/core/src/runtime/utils.rs diff --git a/recursion/core/src/stark/config.rs b/crates/recursion/core/src/stark/config.rs similarity index 71% rename from recursion/core/src/stark/config.rs rename to crates/recursion/core/src/stark/config.rs index 2a774ec437..3713fb2ed3 100644 --- a/recursion/core/src/stark/config.rs +++ b/crates/recursion/core/src/stark/config.rs @@ -4,21 +4,17 @@ use p3_challenger::MultiField32Challenger; use p3_commit::ExtensionMmcs; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; -use p3_fri::BatchOpening; -use p3_fri::CommitPhaseProofStep; -use p3_fri::QueryProof; -use p3_fri::{FriConfig, FriProof, TwoAdicFriPcs, TwoAdicFriPcsProof}; +use p3_fri::{ + BatchOpening, CommitPhaseProofStep, FriConfig, FriProof, QueryProof, TwoAdicFriPcs, + TwoAdicFriPcsProof, +}; use p3_merkle_tree::FieldMerkleTreeMmcs; -use p3_poseidon2::Poseidon2; -use p3_poseidon2::Poseidon2ExternalMatrixGeneral; -use p3_symmetric::Hash; -use p3_symmetric::{MultiField32PaddingFreeSponge, TruncatedPermutation}; -use serde::Deserialize; -use serde::Serialize; -use sp1_core::stark::StarkGenericConfig; +use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +use p3_symmetric::{Hash, MultiField32PaddingFreeSponge, TruncatedPermutation}; +use serde::{Deserialize, Serialize}; +use sp1_stark::StarkGenericConfig; -use super::poseidon2::bn254_poseidon2_rc3; -use super::utils; +use super::{poseidon2::bn254_poseidon2_rc3, utils}; /// A configuration for outer recursion. pub type OuterVal = BabyBear; @@ -48,10 +44,8 @@ pub fn outer_perm() -> OuterPerm { let mut round_constants = bn254_poseidon2_rc3(); let internal_start = ROUNDS_F / 2; let internal_end = (ROUNDS_F / 2) + ROUNDS_P; - let internal_round_constants = round_constants - .drain(internal_start..internal_end) - .map(|vec| vec[0]) - .collect::>(); + let internal_round_constants = + round_constants.drain(internal_start..internal_end).map(|vec| vec[0]).collect::>(); let external_round_constants = round_constants; OuterPerm::new( ROUNDS_F, @@ -77,12 +71,24 @@ pub fn outer_fri_config() -> FriConfig { Err(_) => 25, } }; - FriConfig { - log_blowup: 4, - num_queries, - proof_of_work_bits: 16, - mmcs: challenge_mmcs, - } + FriConfig { log_blowup: 4, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } +} + +/// The FRI config for outer recursion. +pub fn outer_fri_config_with_blowup(log_blowup: usize) -> FriConfig { + let perm = outer_perm(); + let hash = OuterHash::new(perm.clone()).unwrap(); + let compress = OuterCompress::new(perm.clone()); + let challenge_mmcs = OuterChallengeMmcs::new(OuterValMmcs::new(hash, compress)); + let num_queries = if utils::sp1_dev_mode() { + 1 + } else { + match std::env::var("FRI_QUERIES") { + Ok(value) => value.parse().unwrap(), + Err(_) => 100 / log_blowup, + } + }; + FriConfig { log_blowup, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } } #[derive(Deserialize)] @@ -124,6 +130,16 @@ impl BabyBearPoseidon2Outer { let pcs = OuterPcs::new(27, dft, val_mmcs, fri_config); Self { pcs, perm } } + pub fn new_with_log_blowup(log_blowup: usize) -> Self { + let perm = outer_perm(); + let hash = OuterHash::new(perm.clone()).unwrap(); + let compress = OuterCompress::new(perm.clone()); + let val_mmcs = OuterValMmcs::new(hash, compress); + let dft = OuterDft {}; + let fri_config = outer_fri_config_with_blowup(log_blowup); + let pcs = OuterPcs::new(27, dft, val_mmcs, fri_config); + Self { pcs, perm } + } } impl Default for BabyBearPoseidon2Outer { @@ -154,10 +170,5 @@ pub fn test_fri_config() -> FriConfig { let hash = OuterHash::new(perm.clone()).unwrap(); let compress = OuterCompress::new(perm.clone()); let challenge_mmcs = OuterChallengeMmcs::new(OuterValMmcs::new(hash, compress)); - FriConfig { - log_blowup: 1, - num_queries: 1, - proof_of_work_bits: 1, - mmcs: challenge_mmcs, - } + FriConfig { log_blowup: 1, num_queries: 1, proof_of_work_bits: 1, mmcs: challenge_mmcs } } diff --git a/recursion/core/src/stark/mod.rs b/crates/recursion/core/src/stark/mod.rs similarity index 73% rename from recursion/core/src/stark/mod.rs rename to crates/recursion/core/src/stark/mod.rs index 8b63a6a3ae..0c2104b3ea 100644 --- a/recursion/core/src/stark/mod.rs +++ b/crates/recursion/core/src/stark/mod.rs @@ -9,8 +9,7 @@ use crate::{ }; use core::iter::once; use p3_field::{extension::BinomiallyExtendable, PrimeField32}; -use sp1_core::stark::{Chip, StarkGenericConfig, StarkMachine, PROOF_MAX_NUM_PVS}; -use sp1_derive::MachineAir; +use sp1_stark::{Chip, StarkGenericConfig, StarkMachine, PROOF_MAX_NUM_PVS}; use std::marker::PhantomData; use crate::runtime::D; @@ -19,8 +18,8 @@ pub type RecursionAirWideDeg3 = RecursionAir; pub type RecursionAirWideDeg9 = RecursionAir; pub type RecursionAirWideDeg17 = RecursionAir; -#[derive(MachineAir)] -#[sp1_core_path = "sp1_core"] +#[derive(sp1_derive::MachineAir)] +#[sp1_core_path = "sp1_stark"] #[execution_record_path = "crate::runtime::ExecutionRecord"] #[program_path = "crate::runtime::RecursionProgram"] #[builder_path = "crate::air::SP1RecursionAirBuilder"] @@ -39,28 +38,19 @@ pub enum RecursionAir, const DEGREE: u impl, const DEGREE: usize> RecursionAir { /// A recursion machine that can have dynamic trace sizes. pub fn machine>(config: SC) -> StarkMachine { - let chips = Self::get_all() - .into_iter() - .map(Chip::new) - .collect::>(); + let chips = Self::get_all().into_iter().map(Chip::new).collect::>(); StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) } /// A recursion machine with fixed trace sizes tuned to work specifically for the wrap layer. pub fn wrap_machine>(config: SC) -> StarkMachine { - let chips = Self::get_wrap_all() - .into_iter() - .map(Chip::new) - .collect::>(); + let chips = Self::get_wrap_all().into_iter().map(Chip::new).collect::>(); StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) } /// A recursion machine with fixed trace sizes tuned to work specifically for the wrap layer. pub fn wrap_machine_dyn>(config: SC) -> StarkMachine { - let chips = Self::get_wrap_dyn_all() - .into_iter() - .map(Chip::new) - .collect::>(); + let chips = Self::get_wrap_dyn_all().into_iter().map(Chip::new).collect::>(); StarkMachine::new(config, chips, PROOF_MAX_NUM_PVS) } @@ -70,12 +60,8 @@ impl, const DEGREE: usize> RecursionAi fixed_log2_rows: None, _phantom: PhantomData, }))) - .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { - fixed_log2_rows: None, - }))) - .chain(once(RecursionAir::Poseidon2Wide(Poseidon2WideChip::< - DEGREE, - > { + .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { fixed_log2_rows: None }))) + .chain(once(RecursionAir::Poseidon2Wide(Poseidon2WideChip:: { fixed_log2_rows: None, pad: true, }))) @@ -84,12 +70,10 @@ impl, const DEGREE: usize> RecursionAi pad: true, }))) .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) - .chain(once(RecursionAir::ExpReverseBitsLen( - ExpReverseBitsLenChip:: { - fixed_log2_rows: None, - pad: true, - }, - ))) + .chain(once(RecursionAir::ExpReverseBitsLen(ExpReverseBitsLenChip:: { + fixed_log2_rows: None, + pad: true, + }))) .collect() } @@ -99,19 +83,13 @@ impl, const DEGREE: usize> RecursionAi fixed_log2_rows: None, _phantom: PhantomData, }))) - .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { - fixed_log2_rows: None, - }))) - .chain(once(RecursionAir::Multi(MultiChip { + .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { fixed_log2_rows: None }))) + .chain(once(RecursionAir::Multi(MultiChip { fixed_log2_rows: None }))) + .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) + .chain(once(RecursionAir::ExpReverseBitsLen(ExpReverseBitsLenChip:: { fixed_log2_rows: None, + pad: true, }))) - .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) - .chain(once(RecursionAir::ExpReverseBitsLen( - ExpReverseBitsLenChip:: { - fixed_log2_rows: None, - pad: true, - }, - ))) .collect() } @@ -121,12 +99,8 @@ impl, const DEGREE: usize> RecursionAi fixed_log2_rows: Some(20), _phantom: PhantomData, }))) - .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { - fixed_log2_rows: Some(19), - }))) - .chain(once(RecursionAir::Multi(MultiChip { - fixed_log2_rows: Some(17), - }))) + .chain(once(RecursionAir::MemoryGlobal(MemoryGlobalChip { fixed_log2_rows: Some(19) }))) + .chain(once(RecursionAir::Multi(MultiChip { fixed_log2_rows: Some(17) }))) .chain(once(RecursionAir::RangeCheck(RangeCheckChip::default()))) .collect() } diff --git a/recursion/core/src/stark/poseidon2.rs b/crates/recursion/core/src/stark/poseidon2.rs similarity index 51% rename from recursion/core/src/stark/poseidon2.rs rename to crates/recursion/core/src/stark/poseidon2.rs index 637ef38a92..4ffd872c39 100644 --- a/recursion/core/src/stark/poseidon2.rs +++ b/crates/recursion/core/src/stark/poseidon2.rs @@ -1,10 +1,10 @@ use ff::PrimeField as FFPrimeField; -use p3_bn254_fr::Bn254Fr; -use p3_bn254_fr::FFBn254Fr; -use zkhash::ark_ff::BigInteger; -use zkhash::ark_ff::PrimeField; -use zkhash::fields::bn256::FpBN256 as ark_FpBN256; -use zkhash::poseidon2::poseidon2_instance_bn256::RC3; +use p3_bn254_fr::{Bn254Fr, FFBn254Fr}; +use zkhash::{ + ark_ff::{BigInteger, PrimeField}, + fields::bn256::FpBN256 as ark_FpBN256, + poseidon2::poseidon2_instance_bn256::RC3, +}; fn bn254_from_ark_ff(input: ark_FpBN256) -> Bn254Fr { let bytes = input.into_bigint().to_bytes_le(); @@ -18,9 +18,7 @@ fn bn254_from_ark_ff(input: ark_FpBN256) -> Bn254Fr { let value = FFBn254Fr::from_repr(res); if value.is_some().into() { - Bn254Fr { - value: value.unwrap(), - } + Bn254Fr { value: value.unwrap() } } else { panic!("Invalid field element") } @@ -29,12 +27,7 @@ fn bn254_from_ark_ff(input: ark_FpBN256) -> Bn254Fr { pub fn bn254_poseidon2_rc3() -> Vec<[Bn254Fr; 3]> { RC3.iter() .map(|vec| { - vec.iter() - .cloned() - .map(bn254_from_ark_ff) - .collect::>() - .try_into() - .unwrap() + vec.iter().cloned().map(bn254_from_ark_ff).collect::>().try_into().unwrap() }) .collect() } @@ -42,13 +35,8 @@ pub fn bn254_poseidon2_rc3() -> Vec<[Bn254Fr; 3]> { pub fn bn254_poseidon2_rc4() -> Vec<[Bn254Fr; 4]> { RC3.iter() .map(|vec| { - let result: [Bn254Fr; 3] = vec - .iter() - .cloned() - .map(bn254_from_ark_ff) - .collect::>() - .try_into() - .unwrap(); + let result: [Bn254Fr; 3] = + vec.iter().cloned().map(bn254_from_ark_ff).collect::>().try_into().unwrap(); [result[0], result[1], result[2], result[2]] }) .collect() diff --git a/recursion/core/src/stark/utils.rs b/crates/recursion/core/src/stark/utils.rs similarity index 90% rename from recursion/core/src/stark/utils.rs rename to crates/recursion/core/src/stark/utils.rs index f56c546fd0..6e815b05c1 100644 --- a/recursion/core/src/stark/utils.rs +++ b/crates/recursion/core/src/stark/utils.rs @@ -1,15 +1,14 @@ use p3_baby_bear::BabyBear; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::utils; -use sp1_core::utils::BabyBearPoseidon2; +use sp1_core_machine::utils; +use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; -use crate::air::Block; -use crate::runtime::RecursionProgram; -use crate::runtime::Runtime; -use crate::stark::RecursionAirWideDeg3; -use crate::stark::RecursionAirWideDeg9; +use crate::{ + air::Block, + runtime::{RecursionProgram, Runtime}, + stark::{RecursionAirWideDeg3, RecursionAirWideDeg9}, +}; use p3_field::PrimeField32; -use sp1_core::utils::run_test_machine; +use sp1_core_machine::utils::run_test_machine; use std::collections::VecDeque; #[derive(PartialEq, Clone, Debug)] diff --git a/recursion/derive/CHANGELOG.md b/crates/recursion/derive/CHANGELOG.md similarity index 100% rename from recursion/derive/CHANGELOG.md rename to crates/recursion/derive/CHANGELOG.md diff --git a/recursion/derive/Cargo.toml b/crates/recursion/derive/Cargo.toml similarity index 93% rename from recursion/derive/Cargo.toml rename to crates/recursion/derive/Cargo.toml index 44526be4c0..3c3135ba3a 100644 --- a/recursion/derive/Cargo.toml +++ b/crates/recursion/derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-derive" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } diff --git a/recursion/derive/src/lib.rs b/crates/recursion/derive/src/lib.rs similarity index 100% rename from recursion/derive/src/lib.rs rename to crates/recursion/derive/src/lib.rs diff --git a/recursion/gnark-cli/CHANGELOG.md b/crates/recursion/gnark-cli/CHANGELOG.md similarity index 100% rename from recursion/gnark-cli/CHANGELOG.md rename to crates/recursion/gnark-cli/CHANGELOG.md diff --git a/recursion/gnark-cli/Cargo.toml b/crates/recursion/gnark-cli/Cargo.toml similarity index 94% rename from recursion/gnark-cli/Cargo.toml rename to crates/recursion/gnark-cli/Cargo.toml index c43a28566b..ae792552d7 100644 --- a/recursion/gnark-cli/Cargo.toml +++ b/crates/recursion/gnark-cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-gnark-cli" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } diff --git a/crates/recursion/gnark-cli/src/main.rs b/crates/recursion/gnark-cli/src/main.rs new file mode 100644 index 0000000000..ef5c4d9fd6 --- /dev/null +++ b/crates/recursion/gnark-cli/src/main.rs @@ -0,0 +1,136 @@ +//! A simple CLI that wraps the gnark-ffi crate. This is called using Docker in gnark-ffi when the +//! native feature is disabled. + +use sp1_recursion_gnark_ffi::{ + ffi::{ + build_groth16_bn254, build_plonk_bn254, test_groth16_bn254, test_plonk_bn254, + verify_groth16_bn254, verify_plonk_bn254, + }, + ProofBn254, +}; + +use clap::{Args, Parser, Subcommand}; +use std::{ + fs::File, + io::{read_to_string, Write}, +}; + +#[derive(Debug, Parser)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + Build(BuildArgs), + Prove(ProveArgs), + Verify(VerifyArgs), + Test(TestArgs), +} + +#[derive(Debug, Args)] +struct BuildArgs { + data_dir: String, + #[arg(short, long)] + system: String, +} + +#[derive(Debug, Args)] +struct ProveArgs { + data_dir: String, + witness_path: String, + output_path: String, + #[arg(short, long)] + system: String, +} + +#[derive(Debug, Args)] +struct VerifyArgs { + data_dir: String, + proof_path: String, + vkey_hash: String, + committed_values_digest: String, + output_path: String, + #[arg(short, long)] + system: String, +} + +#[derive(Debug, Args)] +struct TestArgs { + witness_json: String, + constraints_json: String, + #[arg(short, long)] + system: String, +} + +fn run_build(args: BuildArgs) { + match args.system.as_str() { + "plonk" => build_plonk_bn254(&args.data_dir), + "groth16" => build_groth16_bn254(&args.data_dir), + _ => panic!("Unsupported system: {}", args.system), + } +} + +fn run_prove(args: ProveArgs) { + let proof = match args.system.as_str() { + "plonk" => prove_plonk_bn254(&args.data_dir, &args.witness_path), + "groth16" => prove_groth16_bn254(&args.data_dir, &args.witness_path), + _ => panic!("Unsupported system: {}", args.system), + }; + let mut file = File::create(&args.output_path).unwrap(); + bincode::serialize_into(&mut file, &proof).unwrap(); +} + +fn prove_plonk_bn254(data_dir: &str, witness_path: &str) -> ProofBn254 { + ProofBn254::Plonk(sp1_recursion_gnark_ffi::ffi::prove_plonk_bn254(data_dir, witness_path)) +} + +fn prove_groth16_bn254(data_dir: &str, witness_path: &str) -> ProofBn254 { + ProofBn254::Groth16(sp1_recursion_gnark_ffi::ffi::prove_groth16_bn254(data_dir, witness_path)) +} + +fn run_verify(args: VerifyArgs) { + let file = File::open(&args.proof_path).unwrap(); + let proof = read_to_string(file).unwrap(); + let result = match args.system.as_str() { + "plonk" => verify_plonk_bn254( + &args.data_dir, + proof.trim(), + &args.vkey_hash, + &args.committed_values_digest, + ), + "groth16" => verify_groth16_bn254( + &args.data_dir, + proof.trim(), + &args.vkey_hash, + &args.committed_values_digest, + ), + _ => panic!("Unsupported system: {}", args.system), + }; + let output = match result { + Ok(_) => "OK".to_string(), + Err(e) => e, + }; + let mut file = File::create(&args.output_path).unwrap(); + file.write_all(output.as_bytes()).unwrap(); +} + +fn run_test(args: TestArgs) { + match args.system.as_str() { + "plonk" => test_plonk_bn254(&args.witness_json, &args.constraints_json), + "groth16" => test_groth16_bn254(&args.witness_json, &args.constraints_json), + _ => panic!("Unsupported system: {}", args.system), + } +} + +fn main() { + let cli = Cli::parse(); + + match cli.command { + Command::Build(args) => run_build(args), + Command::Prove(args) => run_prove(args), + Command::Verify(args) => run_verify(args), + Command::Test(args) => run_test(args), + } +} diff --git a/recursion/gnark-ffi/CHANGELOG.md b/crates/recursion/gnark-ffi/CHANGELOG.md similarity index 100% rename from recursion/gnark-ffi/CHANGELOG.md rename to crates/recursion/gnark-ffi/CHANGELOG.md diff --git a/recursion/gnark-ffi/Cargo.toml b/crates/recursion/gnark-ffi/Cargo.toml similarity index 88% rename from recursion/gnark-ffi/Cargo.toml rename to crates/recursion/gnark-ffi/Cargo.toml index 83df0217fc..ee53b5b4af 100644 --- a/recursion/gnark-ffi/Cargo.toml +++ b/crates/recursion/gnark-ffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-gnark-ffi" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -14,7 +14,8 @@ p3-field = { workspace = true } p3-symmetric = { workspace = true } p3-baby-bear = { workspace = true } sp1-recursion-compiler = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } +sp1-stark = { workspace = true } serde = "1.0.204" serde_json = "1.0.121" tempfile = "3.10.1" diff --git a/recursion/gnark-ffi/assets/SP1Verifier.txt b/crates/recursion/gnark-ffi/assets/SP1Verifier.txt similarity index 94% rename from recursion/gnark-ffi/assets/SP1Verifier.txt rename to crates/recursion/gnark-ffi/assets/SP1Verifier.txt index 0c009135e3..a18f01b819 100644 --- a/recursion/gnark-ffi/assets/SP1Verifier.txt +++ b/crates/recursion/gnark-ffi/assets/SP1Verifier.txt @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol"; -import {PlonkVerifier} from "./PlonkVerifier.sol"; +import {{PROOF_SYSTEM}Verifier} from "./{PROOF_SYSTEM}Verifier.sol"; /// @title SP1 Verifier /// @author Succinct Labs /// @notice This contracts implements a solidity verifier for SP1. -contract SP1Verifier is PlonkVerifier, ISP1VerifierWithHash { +contract SP1Verifier is {PROOF_SYSTEM}Verifier, ISP1VerifierWithHash { /// @notice Thrown when the verifier selector from this proof does not match the one in this /// verifier. This indicates that this proof was sent to the wrong verifier. /// @param received The verifier selector from the first 4 bytes of the proof. @@ -58,4 +58,4 @@ contract SP1Verifier is PlonkVerifier, ISP1VerifierWithHash { revert InvalidProof(); } } -} +} \ No newline at end of file diff --git a/recursion/gnark-ffi/build.rs b/crates/recursion/gnark-ffi/build.rs similarity index 97% rename from recursion/gnark-ffi/build.rs rename to crates/recursion/gnark-ffi/build.rs index 0aa355524a..f08d4df02f 100644 --- a/recursion/gnark-ffi/build.rs +++ b/crates/recursion/gnark-ffi/build.rs @@ -1,9 +1,7 @@ #![allow(unused)] use cfg_if::cfg_if; -use std::env; -use std::path::PathBuf; -use std::process::Command; +use std::{env, path::PathBuf, process::Command}; #[allow(deprecated)] use bindgen::CargoCallbacks; diff --git a/recursion/gnark-ffi/go/.gitignore b/crates/recursion/gnark-ffi/go/.gitignore similarity index 76% rename from recursion/gnark-ffi/go/.gitignore rename to crates/recursion/gnark-ffi/go/.gitignore index b4a997102a..a485d2ce97 100644 --- a/recursion/gnark-ffi/go/.gitignore +++ b/crates/recursion/gnark-ffi/go/.gitignore @@ -1,5 +1,5 @@ constraints.json -witness.json +*witness.json lib/libbabybear.a build/ main \ No newline at end of file diff --git a/recursion/gnark-ffi/go/babybear.h b/crates/recursion/gnark-ffi/go/babybear.h similarity index 100% rename from recursion/gnark-ffi/go/babybear.h rename to crates/recursion/gnark-ffi/go/babybear.h diff --git a/recursion/gnark-ffi/go/go.mod b/crates/recursion/gnark-ffi/go/go.mod similarity index 100% rename from recursion/gnark-ffi/go/go.mod rename to crates/recursion/gnark-ffi/go/go.mod diff --git a/recursion/gnark-ffi/go/go.sum b/crates/recursion/gnark-ffi/go/go.sum similarity index 100% rename from recursion/gnark-ffi/go/go.sum rename to crates/recursion/gnark-ffi/go/go.sum diff --git a/recursion/gnark-ffi/go/main.go b/crates/recursion/gnark-ffi/go/main.go similarity index 70% rename from recursion/gnark-ffi/go/main.go rename to crates/recursion/gnark-ffi/go/main.go index ed782400f2..45b75e95e4 100644 --- a/recursion/gnark-ffi/go/main.go +++ b/crates/recursion/gnark-ffi/go/main.go @@ -8,6 +8,12 @@ typedef struct { char *EncodedProof; char *RawProof; } C_PlonkBn254Proof; + +typedef struct { + char *PublicInputs[2]; + char *EncodedProof; + char *RawProof; +} C_Groth16Bn254Proof; */ import "C" import ( @@ -35,7 +41,7 @@ func ProvePlonkBn254(dataDir *C.char, witnessPath *C.char) *C.C_PlonkBn254Proof dataDirString := C.GoString(dataDir) witnessPathString := C.GoString(witnessPath) - sp1PlonkBn254Proof := sp1.Prove(dataDirString, witnessPathString) + sp1PlonkBn254Proof := sp1.ProvePlonk(dataDirString, witnessPathString) ms := C.malloc(C.sizeof_C_PlonkBn254Proof) if ms == nil { @@ -55,7 +61,7 @@ func BuildPlonkBn254(dataDir *C.char) { // Sanity check the required arguments have been provided. dataDirString := C.GoString(dataDir) - sp1.Build(dataDirString) + sp1.BuildPlonk(dataDirString) } //export VerifyPlonkBn254 @@ -65,7 +71,7 @@ func VerifyPlonkBn254(dataDir *C.char, proof *C.char, vkeyHash *C.char, commited vkeyHashString := C.GoString(vkeyHash) commitedValuesDigestString := C.GoString(commitedValuesDigest) - err := sp1.Verify(dataDirString, proofString, vkeyHashString, commitedValuesDigestString) + err := sp1.VerifyPlonk(dataDirString, proofString, vkeyHashString, commitedValuesDigestString) if err != nil { return C.CString(err.Error()) } @@ -90,11 +96,70 @@ func TestPlonkBn254(witnessPath *C.char, constraintsJson *C.char) *C.char { return nil } +//export ProveGroth16Bn254 +func ProveGroth16Bn254(dataDir *C.char, witnessPath *C.char) *C.C_Groth16Bn254Proof { + dataDirString := C.GoString(dataDir) + witnessPathString := C.GoString(witnessPath) + + sp1Groth16Bn254Proof := sp1.ProveGroth16(dataDirString, witnessPathString) + + ms := C.malloc(C.sizeof_C_Groth16Bn254Proof) + if ms == nil { + return nil + } + + structPtr := (*C.C_Groth16Bn254Proof)(ms) + structPtr.PublicInputs[0] = C.CString(sp1Groth16Bn254Proof.PublicInputs[0]) + structPtr.PublicInputs[1] = C.CString(sp1Groth16Bn254Proof.PublicInputs[1]) + structPtr.EncodedProof = C.CString(sp1Groth16Bn254Proof.EncodedProof) + structPtr.RawProof = C.CString(sp1Groth16Bn254Proof.RawProof) + return structPtr +} + +//export BuildGroth16Bn254 +func BuildGroth16Bn254(dataDir *C.char) { + // Sanity check the required arguments have been provided. + dataDirString := C.GoString(dataDir) + + sp1.BuildGroth16(dataDirString) +} + +//export VerifyGroth16Bn254 +func VerifyGroth16Bn254(dataDir *C.char, proof *C.char, vkeyHash *C.char, committedValuesDigest *C.char) *C.char { + dataDirString := C.GoString(dataDir) + proofString := C.GoString(proof) + vkeyHashString := C.GoString(vkeyHash) + committedValuesDigestString := C.GoString(committedValuesDigest) + + err := sp1.VerifyGroth16(dataDirString, proofString, vkeyHashString, committedValuesDigestString) + if err != nil { + return C.CString(err.Error()) + } + return nil +} + +//export TestGroth16Bn254 +func TestGroth16Bn254(witnessJson *C.char, constraintsJson *C.char) *C.char { + // Because of the global env variables used here, we need to lock this function + testMutex.Lock() + witnessPathString := C.GoString(witnessJson) + constraintsJsonString := C.GoString(constraintsJson) + os.Setenv("WITNESS_JSON", witnessPathString) + os.Setenv("CONSTRAINTS_JSON", constraintsJsonString) + os.Setenv("GROTH16", "1") + err := TestMain() + testMutex.Unlock() + if err != nil { + return C.CString(err.Error()) + } + return nil +} + func TestMain() error { // Get the file name from an environment variable. fileName := os.Getenv("WITNESS_JSON") if fileName == "" { - fileName = "witness.json" + fileName = "plonk_witness.json" } // Read the file. diff --git a/recursion/gnark-ffi/go/main_test.go b/crates/recursion/gnark-ffi/go/main_test.go similarity index 100% rename from recursion/gnark-ffi/go/main_test.go rename to crates/recursion/gnark-ffi/go/main_test.go diff --git a/recursion/gnark-ffi/go/sp1/babybear/babybear.go b/crates/recursion/gnark-ffi/go/sp1/babybear/babybear.go similarity index 93% rename from recursion/gnark-ffi/go/sp1/babybear/babybear.go rename to crates/recursion/gnark-ffi/go/sp1/babybear/babybear.go index 8259d486c7..86e9cda569 100644 --- a/recursion/gnark-ffi/go/sp1/babybear/babybear.go +++ b/crates/recursion/gnark-ffi/go/sp1/babybear/babybear.go @@ -9,6 +9,7 @@ import ( "fmt" "math" "math/big" + "os" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" @@ -53,7 +54,19 @@ func Zero() Variable { } } +func One() Variable { + return Variable{ + Value: frontend.Variable("1"), + NbBits: 1, + } +} + func NewF(value string) Variable { + if value == "0" { + return Zero() + } else if value == "1" { + return One() + } return Variable{ Value: frontend.Variable(value), NbBits: 31, @@ -105,7 +118,7 @@ func (c *Chip) MulFConst(a Variable, b int) Variable { } func (c *Chip) negF(a Variable) Variable { - if a.NbBits == 31 { + if a.NbBits <= 31 { return Variable{Value: c.api.Sub(modulus, a.Value), NbBits: 31} } @@ -137,6 +150,11 @@ func (c *Chip) invF(in Variable) Variable { return xinv } +func (c *Chip) DivF(a, b Variable) Variable { + bInv := c.invF(b) + return c.MulF(a, bInv) +} + func (c *Chip) AssertIsEqualF(a, b Variable) { a2 := c.ReduceSlow(a) b2 := c.ReduceSlow(b) @@ -283,7 +301,7 @@ func (p *Chip) reduceFast(x Variable) Variable { } func (p *Chip) ReduceSlow(x Variable) Variable { - if x.NbBits == 31 { + if x.NbBits <= 31 { return x } return Variable{ @@ -293,16 +311,22 @@ func (p *Chip) ReduceSlow(x Variable) Variable { } func (p *Chip) reduceWithMaxBits(x frontend.Variable, maxNbBits uint64) frontend.Variable { + if maxNbBits <= 31 { + return x + } result, err := p.api.Compiler().NewHint(ReduceHint, 2, x) if err != nil { panic(err) } quotient := result[0] - p.rangeChecker.Check(quotient, int(maxNbBits-31)) - remainder := result[1] + if os.Getenv("GROTH16") != "1" { + p.rangeChecker.Check(quotient, int(maxNbBits-31)) + } else { + p.api.ToBinary(quotient, int(maxNbBits-31)) + } // Check that the remainder has size less than the BabyBear modulus, by decomposing it into a 27 // bit limb and a 4 bit limb. new_result, new_err := p.api.Compiler().NewHint(SplitLimbsHint, 2, remainder) @@ -321,8 +345,13 @@ func (p *Chip) reduceWithMaxBits(x frontend.Variable, maxNbBits uint64) frontend ), remainder, ) - p.rangeChecker.Check(highLimb, 4) - p.rangeChecker.Check(lowLimb, 27) + if os.Getenv("GROTH16") != "1" { + p.rangeChecker.Check(highLimb, 4) + p.rangeChecker.Check(lowLimb, 27) + } else { + p.api.ToBinary(highLimb, 4) + p.api.ToBinary(lowLimb, 27) + } // If the most significant bits are all 1, then we need to check that the least significant bits // are all zero in order for element to be less than the BabyBear modulus. Otherwise, we don't @@ -337,7 +366,7 @@ func (p *Chip) reduceWithMaxBits(x frontend.Variable, maxNbBits uint64) frontend frontend.Variable(0), ) - p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, modulus), result[1])) + p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, modulus), remainder)) return remainder } diff --git a/recursion/gnark-ffi/go/sp1/build.go b/crates/recursion/gnark-ffi/go/sp1/build.go similarity index 58% rename from recursion/gnark-ffi/go/sp1/build.go rename to crates/recursion/gnark-ffi/go/sp1/build.go index 5531b7ebb5..174c3f961f 100644 --- a/recursion/gnark-ffi/go/sp1/build.go +++ b/crates/recursion/gnark-ffi/go/sp1/build.go @@ -9,14 +9,16 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/kzg" + groth16 "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/test/unsafekzg" "github.com/succinctlabs/sp1-recursion-gnark/sp1/trusted_setup" ) -func Build(dataDir string) { +func BuildPlonk(dataDir string) { // Set the enviroment variable for the constraints file. // // TODO: There might be some non-determinism if a single process is running this command @@ -24,7 +26,7 @@ func Build(dataDir string) { os.Setenv("CONSTRAINTS_JSON", dataDir+"/"+constraintsJsonFile) // Read the file. - witnessInputPath := dataDir + "/witness.json" + witnessInputPath := dataDir + "/" + plonkWitnessPath data, err := os.ReadFile(witnessInputPath) if err != nil { panic(err) @@ -152,7 +154,7 @@ func Build(dataDir string) { os.MkdirAll(dataDir, 0755) // Write the solidity verifier. - solidityVerifierFile, err := os.Create(dataDir + "/" + verifierContractPath) + solidityVerifierFile, err := os.Create(dataDir + "/" + plonkVerifierContractPath) if err != nil { panic(err) } @@ -160,7 +162,7 @@ func Build(dataDir string) { defer solidityVerifierFile.Close() // Write the R1CS. - scsFile, err := os.Create(dataDir + "/" + circuitPath) + scsFile, err := os.Create(dataDir + "/" + plonkCircuitPath) if err != nil { panic(err) } @@ -171,7 +173,7 @@ func Build(dataDir string) { } // Write the verifier key. - vkFile, err := os.Create(dataDir + "/" + vkPath) + vkFile, err := os.Create(dataDir + "/" + plonkVkPath) if err != nil { panic(err) } @@ -182,7 +184,110 @@ func Build(dataDir string) { } // Write the proving key. - pkFile, err := os.Create(dataDir + "/" + pkPath) + pkFile, err := os.Create(dataDir + "/" + plonkPkPath) + if err != nil { + panic(err) + } + defer pkFile.Close() + _, err = pk.WriteTo(pkFile) + if err != nil { + panic(err) + } +} + +func BuildGroth16(dataDir string) { + // Set the environment variable for the constraints file. + // + // TODO: There might be some non-determinism if a single process is running this command + // multiple times. + os.Setenv("CONSTRAINTS_JSON", dataDir+"/"+constraintsJsonFile) + os.Setenv("GROTH16", "1") + + // Read the file. + witnessInputPath := dataDir + "/" + groth16WitnessPath + data, err := os.ReadFile(witnessInputPath) + if err != nil { + panic(err) + } + + // Deserialize the JSON data into a slice of Instruction structs + var witnessInput WitnessInput + err = json.Unmarshal(data, &witnessInput) + if err != nil { + panic(err) + } + + // Initialize the circuit. + circuit := NewCircuit(witnessInput) + + // Compile the circuit. + r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } + + // Generate the proving and verifying key. + pk, vk, err := groth16.Setup(r1cs) + if err != nil { + panic(err) + } + + // Generate proof. + assignment := NewCircuit(witnessInput) + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } + proof, err := groth16.Prove(r1cs, pk, witness) + if err != nil { + panic(err) + } + + // Verify proof. + publicWitness, err := witness.Public() + if err != nil { + panic(err) + } + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } + + // Create the build directory. + os.MkdirAll(dataDir, 0755) + + // Write the solidity verifier. + solidityVerifierFile, err := os.Create(dataDir + "/" + groth16VerifierContractPath) + if err != nil { + panic(err) + } + vk.ExportSolidity(solidityVerifierFile) + defer solidityVerifierFile.Close() + + // Write the R1CS. + r1csFile, err := os.Create(dataDir + "/" + groth16CircuitPath) + if err != nil { + panic(err) + } + defer r1csFile.Close() + _, err = r1cs.WriteTo(r1csFile) + if err != nil { + panic(err) + } + + // Write the verifier key. + vkFile, err := os.Create(dataDir + "/" + groth16VkPath) + if err != nil { + panic(err) + } + defer vkFile.Close() + _, err = vk.WriteTo(vkFile) + if err != nil { + panic(err) + } + + // Write the proving key. + pkFile, err := os.Create(dataDir + "/" + groth16PkPath) if err != nil { panic(err) } diff --git a/recursion/gnark-ffi/go/sp1/poseidon2/constants.go b/crates/recursion/gnark-ffi/go/sp1/poseidon2/constants.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/poseidon2/constants.go rename to crates/recursion/gnark-ffi/go/sp1/poseidon2/constants.go diff --git a/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2.go b/crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/poseidon2/poseidon2.go rename to crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2.go diff --git a/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_babybear.go b/crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_babybear.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_babybear.go rename to crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_babybear.go diff --git a/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_test.go b/crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_test.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_test.go rename to crates/recursion/gnark-ffi/go/sp1/poseidon2/poseidon2_test.go diff --git a/recursion/gnark-ffi/go/sp1/poseidon2/utils.go b/crates/recursion/gnark-ffi/go/sp1/poseidon2/utils.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/poseidon2/utils.go rename to crates/recursion/gnark-ffi/go/sp1/poseidon2/utils.go diff --git a/crates/recursion/gnark-ffi/go/sp1/prove.go b/crates/recursion/gnark-ffi/go/sp1/prove.go new file mode 100644 index 0000000000..f474d786a2 --- /dev/null +++ b/crates/recursion/gnark-ffi/go/sp1/prove.go @@ -0,0 +1,161 @@ +package sp1 + +import ( + "bufio" + "encoding/json" + "os" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/frontend" +) + +func ProvePlonk(dataDir string, witnessPath string) Proof { + // Sanity check the required arguments have been provided. + if dataDir == "" { + panic("dataDirStr is required") + } + os.Setenv("CONSTRAINTS_JSON", dataDir+"/"+constraintsJsonFile) + + // Read the R1CS. + scsFile, err := os.Open(dataDir + "/" + plonkCircuitPath) + if err != nil { + panic(err) + } + scs := plonk.NewCS(ecc.BN254) + scs.ReadFrom(scsFile) + defer scsFile.Close() + + // Read the proving key. + pkFile, err := os.Open(dataDir + "/" + plonkPkPath) + if err != nil { + panic(err) + } + pk := plonk.NewProvingKey(ecc.BN254) + bufReader := bufio.NewReaderSize(pkFile, 1024*1024) + pk.UnsafeReadFrom(bufReader) + defer pkFile.Close() + + // Read the verifier key. + vkFile, err := os.Open(dataDir + "/" + plonkVkPath) + if err != nil { + panic(err) + } + vk := plonk.NewVerifyingKey(ecc.BN254) + vk.ReadFrom(vkFile) + defer vkFile.Close() + + // Read the file. + data, err := os.ReadFile(witnessPath) + if err != nil { + panic(err) + } + + // Deserialize the JSON data into a slice of Instruction structs + var witnessInput WitnessInput + err = json.Unmarshal(data, &witnessInput) + if err != nil { + panic(err) + } + + // Generate the witness. + assignment := NewCircuit(witnessInput) + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } + publicWitness, err := witness.Public() + if err != nil { + panic(err) + } + + // Generate the proof. + proof, err := plonk.Prove(scs, pk, witness) + if err != nil { + panic(err) + } + + // Verify proof. + err = plonk.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } + + return NewSP1PlonkBn254Proof(&proof, witnessInput) +} + +func ProveGroth16(dataDir string, witnessPath string) Proof { + // Sanity check the required arguments have been provided. + if dataDir == "" { + panic("dataDirStr is required") + } + os.Setenv("CONSTRAINTS_JSON", dataDir+"/"+constraintsJsonFile) + os.Setenv("GROTH16", "1") + + // Read the R1CS. + r1csFile, err := os.Open(dataDir + "/" + groth16CircuitPath) + if err != nil { + panic(err) + } + r1cs := groth16.NewCS(ecc.BN254) + r1cs.ReadFrom(r1csFile) + defer r1csFile.Close() + + // Read the proving key. + pkFile, err := os.Open(dataDir + "/" + groth16PkPath) + if err != nil { + panic(err) + } + pk := groth16.NewProvingKey(ecc.BN254) + bufReader := bufio.NewReaderSize(pkFile, 1024*1024) + pk.UnsafeReadFrom(bufReader) + defer pkFile.Close() + + // Read the verifier key. + vkFile, err := os.Open(dataDir + "/" + groth16VkPath) + if err != nil { + panic(err) + } + vk := groth16.NewVerifyingKey(ecc.BN254) + vk.ReadFrom(vkFile) + defer vkFile.Close() + + // Read the file. + data, err := os.ReadFile(witnessPath) + if err != nil { + panic(err) + } + + // Deserialize the JSON data into a slice of Instruction structs + var witnessInput WitnessInput + err = json.Unmarshal(data, &witnessInput) + if err != nil { + panic(err) + } + + // Generate the witness. + assignment := NewCircuit(witnessInput) + witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } + publicWitness, err := witness.Public() + if err != nil { + panic(err) + } + + // Generate the proof. + proof, err := groth16.Prove(r1cs, pk, witness) + if err != nil { + panic(err) + } + + // Verify proof. + err = groth16.Verify(proof, vk, publicWitness) + if err != nil { + panic(err) + } + + return NewSP1Groth16Proof(&proof, witnessInput) +} diff --git a/recursion/gnark-ffi/go/sp1/sp1.go b/crates/recursion/gnark-ffi/go/sp1/sp1.go similarity index 89% rename from recursion/gnark-ffi/go/sp1/sp1.go rename to crates/recursion/gnark-ffi/go/sp1/sp1.go index 5760a43d90..3b01e19820 100644 --- a/recursion/gnark-ffi/go/sp1/sp1.go +++ b/crates/recursion/gnark-ffi/go/sp1/sp1.go @@ -14,10 +14,16 @@ import ( var srsFile string = "srs.bin" var srsLagrangeFile string = "srs_lagrange.bin" var constraintsJsonFile string = "constraints.json" -var verifierContractPath string = "PlonkVerifier.sol" -var circuitPath string = "circuit.bin" -var vkPath string = "vk.bin" -var pkPath string = "pk.bin" +var plonkVerifierContractPath string = "PlonkVerifier.sol" +var groth16VerifierContractPath string = "Groth16Verifier.sol" +var plonkCircuitPath string = "plonk_circuit.bin" +var groth16CircuitPath string = "groth16_circuit.bin" +var plonkVkPath string = "plonk_vk.bin" +var groth16VkPath string = "groth16_vk.bin" +var plonkPkPath string = "plonk_pk.bin" +var groth16PkPath string = "groth16_pk.bin" +var plonkWitnessPath string = "plonk_witness.json" +var groth16WitnessPath string = "groth16_witness.json" type Circuit struct { VkeyHash frontend.Variable `gnark:",public"` @@ -94,6 +100,8 @@ func (circuit *Circuit) Define(api frontend.API) error { vars[cs.Args[0][0]] = api.Sub(vars[cs.Args[1][0]], vars[cs.Args[2][0]]) case "SubF": felts[cs.Args[0][0]] = fieldAPI.SubF(felts[cs.Args[1][0]], felts[cs.Args[2][0]]) + case "DivF": + felts[cs.Args[0][0]] = fieldAPI.DivF(felts[cs.Args[1][0]], felts[cs.Args[2][0]]) case "SubE": exts[cs.Args[0][0]] = fieldAPI.SubE(exts[cs.Args[1][0]], exts[cs.Args[2][0]]) case "SubEF": @@ -161,10 +169,10 @@ func (circuit *Circuit) Define(api frontend.API) error { case "PrintV": api.Println(vars[cs.Args[0][0]]) case "PrintF": - f := felts[cs.Args[0][0]] + f := fieldAPI.ReduceSlow(felts[cs.Args[0][0]]) api.Println(f.Value) case "PrintE": - e := exts[cs.Args[0][0]] + e := fieldAPI.ReduceE(exts[cs.Args[0][0]]) api.Println(e.Value[0].Value) api.Println(e.Value[1].Value) api.Println(e.Value[2].Value) @@ -195,6 +203,8 @@ func (circuit *Circuit) Define(api frontend.API) error { api.AssertIsEqual(circuit.CommitedValuesDigest, element) case "CircuitFelts2Ext": exts[cs.Args[0][0]] = babybear.Felts2Ext(felts[cs.Args[1][0]], felts[cs.Args[2][0]], felts[cs.Args[3][0]], felts[cs.Args[4][0]]) + case "CircuitFelt2Var": + vars[cs.Args[0][0]] = fieldAPI.ReduceSlow(felts[cs.Args[1][0]]).Value case "ReduceE": exts[cs.Args[0][0]] = fieldAPI.ReduceE(exts[cs.Args[0][0]]) default: diff --git a/recursion/gnark-ffi/go/sp1/test.go b/crates/recursion/gnark-ffi/go/sp1/test.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/test.go rename to crates/recursion/gnark-ffi/go/sp1/test.go diff --git a/recursion/gnark-ffi/go/sp1/trusted_setup/trusted_setup.go b/crates/recursion/gnark-ffi/go/sp1/trusted_setup/trusted_setup.go similarity index 100% rename from recursion/gnark-ffi/go/sp1/trusted_setup/trusted_setup.go rename to crates/recursion/gnark-ffi/go/sp1/trusted_setup/trusted_setup.go diff --git a/recursion/gnark-ffi/go/sp1/utils.go b/crates/recursion/gnark-ffi/go/sp1/utils.go similarity index 69% rename from recursion/gnark-ffi/go/sp1/utils.go rename to crates/recursion/gnark-ffi/go/sp1/utils.go index f4711d9c61..6456c90b2a 100644 --- a/recursion/gnark-ffi/go/sp1/utils.go +++ b/crates/recursion/gnark-ffi/go/sp1/utils.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/hex" + groth16 "github.com/consensys/gnark/backend/groth16" + groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254" plonk "github.com/consensys/gnark/backend/plonk" plonk_bn254 "github.com/consensys/gnark/backend/plonk/bn254" "github.com/consensys/gnark/frontend" @@ -31,6 +33,27 @@ func NewSP1PlonkBn254Proof(proof *plonk.Proof, witnessInput WitnessInput) Proof } } +func NewSP1Groth16Proof(proof *groth16.Proof, witnessInput WitnessInput) Proof { + var buf bytes.Buffer + (*proof).WriteRawTo(&buf) + proofBytes := buf.Bytes() + + var publicInputs [2]string + publicInputs[0] = witnessInput.VkeyHash + publicInputs[1] = witnessInput.CommitedValuesDigest + + // Cast groth16 proof into groth16_bn254 proof so we can call MarshalSolidity. + p := (*proof).(*groth16_bn254.Proof) + + encodedProof := p.MarshalSolidity() + + return Proof{ + PublicInputs: publicInputs, + EncodedProof: hex.EncodeToString(encodedProof), + RawProof: hex.EncodeToString(proofBytes), + } +} + func NewCircuit(witnessInput WitnessInput) Circuit { vars := make([]frontend.Variable, len(witnessInput.Vars)) felts := make([]babybear.Variable, len(witnessInput.Felts)) diff --git a/crates/recursion/gnark-ffi/go/sp1/verify.go b/crates/recursion/gnark-ffi/go/sp1/verify.go new file mode 100644 index 0000000000..273e854d11 --- /dev/null +++ b/crates/recursion/gnark-ffi/go/sp1/verify.go @@ -0,0 +1,105 @@ +package sp1 + +import ( + "bytes" + "encoding/hex" + "os" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/frontend" + "github.com/succinctlabs/sp1-recursion-gnark/sp1/babybear" +) + +func VerifyPlonk(verifyCmdDataDir string, verifyCmdProof string, verifyCmdVkeyHash string, verifyCmdCommitedValuesDigest string) error { + // Sanity check the required arguments have been provided. + if verifyCmdDataDir == "" { + panic("--data is required") + } + + // Decode the proof. + proofDecodedBytes, err := hex.DecodeString(verifyCmdProof) + if err != nil { + panic(err) + } + proof := plonk.NewProof(ecc.BN254) + if _, err := proof.ReadFrom(bytes.NewReader(proofDecodedBytes)); err != nil { + panic(err) + } + + // Read the verifier key. + vkFile, err := os.Open(verifyCmdDataDir + "/" + plonkVkPath) + if err != nil { + panic(err) + } + vk := plonk.NewVerifyingKey(ecc.BN254) + vk.ReadFrom(vkFile) + + // Compute the public witness. + circuit := Circuit{ + Vars: []frontend.Variable{}, + Felts: []babybear.Variable{}, + Exts: []babybear.ExtensionVariable{}, + VkeyHash: verifyCmdVkeyHash, + CommitedValuesDigest: verifyCmdCommitedValuesDigest, + } + witness, err := frontend.NewWitness(&circuit, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } + publicWitness, err := witness.Public() + if err != nil { + panic(err) + } + + // Verify proof. + err = plonk.Verify(proof, vk, publicWitness) + return err +} + +func VerifyGroth16(verifyCmdDataDir string, verifyCmdProof string, verifyCmdVkeyHash string, verifyCmdCommitedValuesDigest string) error { + // Sanity check the required arguments have been provided. + if verifyCmdDataDir == "" { + panic("--data is required") + } + + // Decode the proof. + proofDecodedBytes, err := hex.DecodeString(verifyCmdProof) + if err != nil { + panic(err) + } + proof := groth16.NewProof(ecc.BN254) + if _, err := proof.ReadFrom(bytes.NewReader(proofDecodedBytes)); err != nil { + panic(err) + } + + // Read the verifier key. + vkFile, err := os.Open(verifyCmdDataDir + "/" + groth16VkPath) + if err != nil { + panic(err) + } + vk := groth16.NewVerifyingKey(ecc.BN254) + vk.ReadFrom(vkFile) + + // Compute the public witness. + circuit := Circuit{ + Vars: []frontend.Variable{}, + Felts: []babybear.Variable{}, + Exts: []babybear.ExtensionVariable{}, + VkeyHash: verifyCmdVkeyHash, + CommitedValuesDigest: verifyCmdCommitedValuesDigest, + } + witness, err := frontend.NewWitness(&circuit, ecc.BN254.ScalarField()) + if err != nil { + panic(err) + } + publicWitness, err := witness.Public() + if err != nil { + panic(err) + } + + // Verify proof. + err = groth16.Verify(proof, vk, publicWitness) + return err +} diff --git a/recursion/gnark-ffi/src/babybear.rs b/crates/recursion/gnark-ffi/src/babybear.rs similarity index 86% rename from recursion/gnark-ffi/src/babybear.rs rename to crates/recursion/gnark-ffi/src/babybear.rs index b0defcc5f8..83417cc9a1 100644 --- a/recursion/gnark-ffi/src/babybear.rs +++ b/crates/recursion/gnark-ffi/src/babybear.rs @@ -1,6 +1,7 @@ use p3_baby_bear::BabyBear; -use p3_field::PrimeField32; -use p3_field::{extension::BinomialExtensionField, AbstractExtensionField, AbstractField, Field}; +use p3_field::{ + extension::BinomialExtensionField, AbstractExtensionField, AbstractField, Field, PrimeField32, +}; #[no_mangle] pub extern "C" fn babybearextinv(a: u32, b: u32, c: u32, d: u32, i: u32) -> u32 { diff --git a/crates/recursion/gnark-ffi/src/ffi/docker.rs b/crates/recursion/gnark-ffi/src/ffi/docker.rs new file mode 100644 index 0000000000..119253d492 --- /dev/null +++ b/crates/recursion/gnark-ffi/src/ffi/docker.rs @@ -0,0 +1,180 @@ +use crate::ProofBn254; +use crate::{Groth16Bn254Proof, PlonkBn254Proof}; +use anyhow::{anyhow, Result}; +use sp1_core_machine::SP1_CIRCUIT_VERSION; +use std::{io::Write, process::Command}; + +/// Represents the proof system being used +enum ProofSystem { + Plonk, + Groth16, +} + +impl ProofSystem { + fn as_str(&self) -> &'static str { + match self { + ProofSystem::Plonk => "plonk", + ProofSystem::Groth16 => "groth16", + } + } +} + +/// Checks that docker is installed and running. +fn check_docker() -> bool { + let output = Command::new("docker").arg("info").output(); + output.is_ok() && output.unwrap().status.success() +} + +/// Panics if docker is not installed and running. +fn assert_docker() { + if !check_docker() { + panic!("Failed to run `docker info`. Please ensure that docker is installed and running."); + } +} + +fn get_docker_image() -> String { + std::env::var("SP1_GNARK_IMAGE") + .unwrap_or_else(|_| format!("ghcr.io/succinctlabs/sp1-gnark:{}", SP1_CIRCUIT_VERSION)) +} + +/// Calls `docker run` with the given arguments and bind mounts. +fn call_docker(args: &[&str], mounts: &[(&str, &str)]) -> Result<()> { + log::info!("Running {} in docker", args[0]); + let mut cmd = Command::new("docker"); + cmd.args(["run", "--rm"]); + for (src, dest) in mounts { + cmd.arg("-v").arg(format!("{}:{}", src, dest)); + } + cmd.arg(get_docker_image()); + cmd.args(args); + if !cmd.status()?.success() { + log::error!("Failed to run `docker run`: {:?}", cmd); + return Err(anyhow!("docker command failed")); + } + Ok(()) +} + +fn prove(system: ProofSystem, data_dir: &str, witness_path: &str) -> Result> { + let output_file = tempfile::NamedTempFile::new()?; + let mounts = [ + (data_dir, "/circuit"), + (witness_path, "/witness"), + (output_file.path().to_str().unwrap(), "/output"), + ]; + assert_docker(); + call_docker( + &["prove", "--system", system.as_str(), "/circuit", "/witness", "/output"], + &mounts, + )?; + Ok(std::fs::read(output_file.path())?) +} + +pub fn prove_plonk_bn254(data_dir: &str, witness_path: &str) -> PlonkBn254Proof { + let result = + prove(ProofSystem::Plonk, data_dir, witness_path).expect("failed to prove with docker"); + let deserialized: ProofBn254 = + bincode::deserialize(&result).expect("failed to deserialize result"); + match deserialized { + ProofBn254::Plonk(proof) => proof, + _ => panic!("unexpected proof type"), + } +} + +pub fn prove_groth16_bn254(data_dir: &str, witness_path: &str) -> Groth16Bn254Proof { + let result = + prove(ProofSystem::Groth16, data_dir, witness_path).expect("failed to prove with docker"); + let deserialized: ProofBn254 = + bincode::deserialize(&result).expect("failed to deserialize result"); + match deserialized { + ProofBn254::Groth16(proof) => proof, + _ => panic!("unexpected proof type"), + } +} + +fn build(system: ProofSystem, data_dir: &str) -> Result<()> { + let circuit_dir = if data_dir.ends_with("dev") { "/circuit_dev" } else { "/circuit" }; + let mounts = [(data_dir, circuit_dir)]; + assert_docker(); + call_docker(&["build", "--system", system.as_str(), circuit_dir], &mounts) +} + +pub fn build_plonk_bn254(data_dir: &str) { + build(ProofSystem::Plonk, data_dir).expect("failed to build with docker"); +} + +pub fn build_groth16_bn254(data_dir: &str) { + build(ProofSystem::Groth16, data_dir).expect("failed to build with docker"); +} + +fn verify( + system: ProofSystem, + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<()> { + let mut proof_file = tempfile::NamedTempFile::new()?; + proof_file.write_all(proof.as_bytes())?; + let output_file = tempfile::NamedTempFile::new()?; + let mounts = [ + (data_dir, "/circuit"), + (proof_file.path().to_str().unwrap(), "/proof"), + (output_file.path().to_str().unwrap(), "/output"), + ]; + assert_docker(); + call_docker( + &[ + "verify", + "--system", + system.as_str(), + "/circuit", + "/proof", + vkey_hash, + committed_values_digest, + "/output", + ], + &mounts, + )?; + let result = std::fs::read_to_string(output_file.path())?; + if result == "OK" { + Ok(()) + } else { + Err(anyhow!(result)) + } +} + +pub fn verify_plonk_bn254( + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<()> { + verify(ProofSystem::Plonk, data_dir, proof, vkey_hash, committed_values_digest) +} + +pub fn verify_groth16_bn254( + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<()> { + verify(ProofSystem::Groth16, data_dir, proof, vkey_hash, committed_values_digest) +} + +fn test(system: ProofSystem, witness_json: &str, constraints_json: &str) -> Result<()> { + let mounts = [(constraints_json, "/constraints"), (witness_json, "/witness")]; + assert_docker(); + call_docker(&["test", "--system", system.as_str(), "/constraints", "/witness"], &mounts) +} + +pub fn test_plonk_bn254(witness_json: &str, constraints_json: &str) { + test(ProofSystem::Plonk, witness_json, constraints_json).expect("failed to test with docker"); +} + +pub fn test_groth16_bn254(witness_json: &str, constraints_json: &str) { + test(ProofSystem::Groth16, witness_json, constraints_json).expect("failed to test with docker"); +} + +pub fn test_babybear_poseidon2() { + unimplemented!() +} diff --git a/recursion/gnark-ffi/src/ffi/mod.rs b/crates/recursion/gnark-ffi/src/ffi/mod.rs similarity index 100% rename from recursion/gnark-ffi/src/ffi/mod.rs rename to crates/recursion/gnark-ffi/src/ffi/mod.rs diff --git a/crates/recursion/gnark-ffi/src/ffi/native.rs b/crates/recursion/gnark-ffi/src/ffi/native.rs new file mode 100644 index 0000000000..d3faba0fe8 --- /dev/null +++ b/crates/recursion/gnark-ffi/src/ffi/native.rs @@ -0,0 +1,259 @@ +#![allow(unused)] + +//! FFI bindings for the Go code. The functions exported in this module are safe to call from Rust. +//! All C strings and other C memory should be freed in Rust, including C Strings returned by Go. +//! Although we cast to *mut c_char because the Go signatures can't be immutable, the Go functions +//! should not modify the strings. + +use crate::{Groth16Bn254Proof, PlonkBn254Proof}; +use cfg_if::cfg_if; +use sp1_core_machine::SP1_CIRCUIT_VERSION; +use std::ffi::{c_char, CString}; + +#[allow(warnings, clippy::all)] +mod bind { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} +use bind::*; + +enum ProofSystem { + Plonk, + Groth16, +} + +enum ProofResult { + Plonk(C_PlonkBn254Proof), + Groth16(C_Groth16Bn254Proof), +} + +impl ProofSystem { + fn build_fn(&self) -> unsafe extern "C" fn(*mut c_char) { + match self { + ProofSystem::Plonk => bind::BuildPlonkBn254, + ProofSystem::Groth16 => bind::BuildGroth16Bn254, + } + } + + fn prove_fn(&self) -> ProveFunction { + match self { + ProofSystem::Plonk => ProveFunction::Plonk(bind::ProvePlonkBn254), + ProofSystem::Groth16 => ProveFunction::Groth16(bind::ProveGroth16Bn254), + } + } + + fn verify_fn( + &self, + ) -> unsafe extern "C" fn(*mut c_char, *mut c_char, *mut c_char, *mut c_char) -> *mut c_char + { + match self { + ProofSystem::Plonk => bind::VerifyPlonkBn254, + ProofSystem::Groth16 => bind::VerifyGroth16Bn254, + } + } + + fn test_fn(&self) -> unsafe extern "C" fn(*mut c_char, *mut c_char) -> *mut c_char { + match self { + ProofSystem::Plonk => bind::TestPlonkBn254, + ProofSystem::Groth16 => bind::TestGroth16Bn254, + } + } +} + +enum ProveFunction { + Plonk(unsafe extern "C" fn(*mut c_char, *mut c_char) -> *mut C_PlonkBn254Proof), + Groth16(unsafe extern "C" fn(*mut c_char, *mut c_char) -> *mut C_Groth16Bn254Proof), +} + +fn build(system: ProofSystem, data_dir: &str) { + let data_dir = CString::new(data_dir).expect("CString::new failed"); + unsafe { + (system.build_fn())(data_dir.as_ptr() as *mut c_char); + } +} + +fn prove(system: ProofSystem, data_dir: &str, witness_path: &str) -> ProofResult { + let data_dir = CString::new(data_dir).expect("CString::new failed"); + let witness_path = CString::new(witness_path).expect("CString::new failed"); + + unsafe { + match system.prove_fn() { + ProveFunction::Plonk(func) => { + let proof = + func(data_dir.as_ptr() as *mut c_char, witness_path.as_ptr() as *mut c_char); + ProofResult::Plonk(*proof) + } + ProveFunction::Groth16(func) => { + let proof = + func(data_dir.as_ptr() as *mut c_char, witness_path.as_ptr() as *mut c_char); + ProofResult::Groth16(*proof) + } + } + } +} + +fn verify( + system: ProofSystem, + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<(), String> { + let data_dir = CString::new(data_dir).expect("CString::new failed"); + let proof = CString::new(proof).expect("CString::new failed"); + let vkey_hash = CString::new(vkey_hash).expect("CString::new failed"); + let committed_values_digest = + CString::new(committed_values_digest).expect("CString::new failed"); + + let err_ptr = unsafe { + (system.verify_fn())( + data_dir.as_ptr() as *mut c_char, + proof.as_ptr() as *mut c_char, + vkey_hash.as_ptr() as *mut c_char, + committed_values_digest.as_ptr() as *mut c_char, + ) + }; + if err_ptr.is_null() { + Ok(()) + } else { + // Safety: The error message is returned from the go code and is guaranteed to be valid. + let err = unsafe { CString::from_raw(err_ptr) }; + Err(err.into_string().unwrap()) + } +} + +fn test(system: ProofSystem, witness_json: &str, constraints_json: &str) { + unsafe { + let witness_json = CString::new(witness_json).expect("CString::new failed"); + let constraints_json = CString::new(constraints_json).expect("CString::new failed"); + let err_ptr = (system.test_fn())( + witness_json.as_ptr() as *mut c_char, + constraints_json.as_ptr() as *mut c_char, + ); + if !err_ptr.is_null() { + // Safety: The error message is returned from the go code and is guaranteed to be valid. + let err = CString::from_raw(err_ptr); + panic!("Test failed: {}", err.into_string().unwrap()); + } + } +} + +// Public API functions + +pub fn build_plonk_bn254(data_dir: &str) { + build(ProofSystem::Plonk, data_dir) +} + +pub fn prove_plonk_bn254(data_dir: &str, witness_path: &str) -> PlonkBn254Proof { + match prove(ProofSystem::Plonk, data_dir, witness_path) { + ProofResult::Plonk(proof) => proof.into(), + _ => unreachable!(), + } +} + +pub fn verify_plonk_bn254( + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<(), String> { + verify(ProofSystem::Plonk, data_dir, proof, vkey_hash, committed_values_digest) +} + +pub fn test_plonk_bn254(witness_json: &str, constraints_json: &str) { + test(ProofSystem::Plonk, witness_json, constraints_json) +} + +pub fn build_groth16_bn254(data_dir: &str) { + build(ProofSystem::Groth16, data_dir) +} + +pub fn prove_groth16_bn254(data_dir: &str, witness_path: &str) -> Groth16Bn254Proof { + match prove(ProofSystem::Groth16, data_dir, witness_path) { + ProofResult::Groth16(proof) => proof.into(), + _ => unreachable!(), + } +} + +pub fn verify_groth16_bn254( + data_dir: &str, + proof: &str, + vkey_hash: &str, + committed_values_digest: &str, +) -> Result<(), String> { + verify(ProofSystem::Groth16, data_dir, proof, vkey_hash, committed_values_digest) +} + +pub fn test_groth16_bn254(witness_json: &str, constraints_json: &str) { + test(ProofSystem::Groth16, witness_json, constraints_json) +} + +pub fn test_babybear_poseidon2() { + unsafe { + let err_ptr = bind::TestPoseidonBabyBear2(); + if !err_ptr.is_null() { + // Safety: The error message is returned from the go code and is guaranteed to be valid. + let err = CString::from_raw(err_ptr); + panic!("TestPoseidonBabyBear2 failed: {}", err.into_string().unwrap()); + } + } +} + +/// Converts a C string into a Rust String. +/// +/// # Safety +/// This function frees the string memory, so the caller must ensure that the pointer is not used +/// after this function is called. +unsafe fn c_char_ptr_to_string(input: *mut c_char) -> String { + CString::from_raw(input).into_string().expect("CString::into_string failed") +} + +impl From for PlonkBn254Proof { + fn from(c_proof: C_PlonkBn254Proof) -> Self { + // Safety: The raw pointers are not used anymore after converted into Rust strings. + unsafe { + PlonkBn254Proof { + public_inputs: [ + c_char_ptr_to_string(c_proof.PublicInputs[0]), + c_char_ptr_to_string(c_proof.PublicInputs[1]), + ], + encoded_proof: c_char_ptr_to_string(c_proof.EncodedProof), + raw_proof: c_char_ptr_to_string(c_proof.RawProof), + plonk_vkey_hash: [0; 32], + } + } + } +} + +impl From for Groth16Bn254Proof { + fn from(c_proof: C_Groth16Bn254Proof) -> Self { + // Safety: The raw pointers are not used anymore after converted into Rust strings. + unsafe { + Groth16Bn254Proof { + public_inputs: [ + c_char_ptr_to_string(c_proof.PublicInputs[0]), + c_char_ptr_to_string(c_proof.PublicInputs[1]), + ], + encoded_proof: c_char_ptr_to_string(c_proof.EncodedProof), + raw_proof: c_char_ptr_to_string(c_proof.RawProof), + groth16_vkey_hash: [0; 32], + } + } + } +} + +#[cfg(test)] +mod tests { + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_symmetric::Permutation; + use sp1_stark::inner_perm; + + #[test] + pub fn test_babybear_poseidon2() { + let perm = inner_perm(); + let zeros = [BabyBear::zero(); 16]; + let result = perm.permute(zeros); + println!("{:?}", result); + super::test_babybear_poseidon2(); + } +} diff --git a/crates/recursion/gnark-ffi/src/groth16_bn254.rs b/crates/recursion/gnark-ffi/src/groth16_bn254.rs new file mode 100644 index 0000000000..2ea1f299f0 --- /dev/null +++ b/crates/recursion/gnark-ffi/src/groth16_bn254.rs @@ -0,0 +1,129 @@ +use std::{ + fs::File, + io::Write, + path::{Path, PathBuf}, +}; + +use crate::{ + ffi::{build_groth16_bn254, prove_groth16_bn254, test_groth16_bn254, verify_groth16_bn254}, + witness::GnarkWitness, + Groth16Bn254Proof, +}; + +use num_bigint::BigUint; +use sha2::{Digest, Sha256}; +use sp1_core_machine::SP1_CIRCUIT_VERSION; +use sp1_recursion_compiler::{ + constraints::Constraint, + ir::{Config, Witness}, +}; + +/// A prover that can generate proofs with the PLONK protocol using bindings to Gnark. +#[derive(Debug, Clone)] +pub struct Groth16Bn254Prover; + +/// A prover that can generate proofs with the Groth16 protocol using bindings to Gnark. +impl Groth16Bn254Prover { + /// Creates a new [Groth16Bn254Prover]. + pub fn new() -> Self { + Self + } + + pub fn get_vkey_hash(build_dir: &Path) -> [u8; 32] { + let vkey_path = build_dir.join("groth16_vk.bin"); + let vk_bin_bytes = std::fs::read(vkey_path).unwrap(); + Sha256::digest(vk_bin_bytes).into() + } + + /// Executes the prover in testing mode with a circuit definition and witness. + pub fn test(constraints: Vec, witness: Witness) { + let serialized = serde_json::to_string(&constraints).unwrap(); + + // Write constraints. + let mut constraints_file = tempfile::NamedTempFile::new().unwrap(); + constraints_file.write_all(serialized.as_bytes()).unwrap(); + + // Write witness. + let mut witness_file = tempfile::NamedTempFile::new().unwrap(); + let gnark_witness = GnarkWitness::new(witness); + let serialized = serde_json::to_string(&gnark_witness).unwrap(); + witness_file.write_all(serialized.as_bytes()).unwrap(); + + test_groth16_bn254( + witness_file.path().to_str().unwrap(), + constraints_file.path().to_str().unwrap(), + ) + } + + /// Builds the Groth16 circuit locally. + pub fn build(constraints: Vec, witness: Witness, build_dir: PathBuf) { + let serialized = serde_json::to_string(&constraints).unwrap(); + + // Write constraints. + let constraints_path = build_dir.join("constraints.json"); + let mut file = File::create(constraints_path).unwrap(); + file.write_all(serialized.as_bytes()).unwrap(); + + // Write witness. + let witness_path = build_dir.join("groth16_witness.json"); + let gnark_witness = GnarkWitness::new(witness); + let mut file = File::create(witness_path).unwrap(); + let serialized = serde_json::to_string(&gnark_witness).unwrap(); + file.write_all(serialized.as_bytes()).unwrap(); + + build_groth16_bn254(build_dir.to_str().unwrap()); + + // Write the corresponding asset files to the build dir. + let sp1_verifier_path = build_dir.join("SP1VerifierGroth16.sol"); + let vkey_hash = Self::get_vkey_hash(&build_dir); + let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt") + .replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION) + .replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str()) + .replace("{PROOF_SYSTEM}", "Groth16"); + let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap(); + sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap(); + } + + /// Generates a Groth16 proof given a witness. + pub fn prove(&self, witness: Witness, build_dir: PathBuf) -> Groth16Bn254Proof { + // Write witness. + let mut witness_file = tempfile::NamedTempFile::new().unwrap(); + let gnark_witness = GnarkWitness::new(witness); + let serialized = serde_json::to_string(&gnark_witness).unwrap(); + witness_file.write_all(serialized.as_bytes()).unwrap(); + + let mut proof = + prove_groth16_bn254(build_dir.to_str().unwrap(), witness_file.path().to_str().unwrap()); + proof.groth16_vkey_hash = Self::get_vkey_hash(&build_dir); + proof + } + + /// Verify a Groth16proof and verify that the supplied vkey_hash and committed_values_digest + /// match. + pub fn verify( + &self, + proof: &Groth16Bn254Proof, + vkey_hash: &BigUint, + committed_values_digest: &BigUint, + build_dir: &Path, + ) { + if proof.groth16_vkey_hash != Self::get_vkey_hash(build_dir) { + panic!( + "Proof vkey hash does not match circuit vkey hash, it was generated with a different circuit." + ); + } + verify_groth16_bn254( + build_dir.to_str().unwrap(), + &proof.raw_proof, + &vkey_hash.to_string(), + &committed_values_digest.to_string(), + ) + .expect("failed to verify proof") + } +} + +impl Default for Groth16Bn254Prover { + fn default() -> Self { + Self::new() + } +} diff --git a/recursion/gnark-ffi/src/lib.rs b/crates/recursion/gnark-ffi/src/lib.rs similarity index 57% rename from recursion/gnark-ffi/src/lib.rs rename to crates/recursion/gnark-ffi/src/lib.rs index 670a9b08fe..436739ba83 100644 --- a/recursion/gnark-ffi/src/lib.rs +++ b/crates/recursion/gnark-ffi/src/lib.rs @@ -1,9 +1,12 @@ mod babybear; pub mod ffi; - +pub mod groth16_bn254; pub mod plonk_bn254; +pub mod proof; pub mod witness; +pub use groth16_bn254::*; pub use plonk_bn254::*; +pub use proof::*; pub use witness::*; diff --git a/recursion/gnark-ffi/src/plonk_bn254.rs b/crates/recursion/gnark-ffi/src/plonk_bn254.rs similarity index 75% rename from recursion/gnark-ffi/src/plonk_bn254.rs rename to crates/recursion/gnark-ffi/src/plonk_bn254.rs index 2b7c071f6c..d719d1ae80 100644 --- a/recursion/gnark-ffi/src/plonk_bn254.rs +++ b/crates/recursion/gnark-ffi/src/plonk_bn254.rs @@ -4,14 +4,15 @@ use std::{ path::{Path, PathBuf}, }; -use crate::ffi::{build_plonk_bn254, prove_plonk_bn254, test_plonk_bn254, verify_plonk_bn254}; -use crate::witness::GnarkWitness; +use crate::{ + ffi::{build_plonk_bn254, prove_plonk_bn254, test_plonk_bn254, verify_plonk_bn254}, + witness::GnarkWitness, + PlonkBn254Proof, +}; use num_bigint::BigUint; -use serde::{Deserialize, Serialize}; -use sha2::Digest; -use sha2::Sha256; -use sp1_core::SP1_CIRCUIT_VERSION; +use sha2::{Digest, Sha256}; +use sp1_core_machine::SP1_CIRCUIT_VERSION; use sp1_recursion_compiler::{ constraints::Constraint, ir::{Config, Witness}, @@ -21,15 +22,6 @@ use sp1_recursion_compiler::{ #[derive(Debug, Clone)] pub struct PlonkBn254Prover; -/// A zero-knowledge proof generated by the PLONK protocol with a Base64 encoded gnark PLONK proof. -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct PlonkBn254Proof { - pub public_inputs: [String; 2], - pub encoded_proof: String, - pub raw_proof: String, - pub plonk_vkey_hash: [u8; 32], -} - impl PlonkBn254Prover { /// Creates a new [PlonkBn254Prover]. pub fn new() -> Self { @@ -37,7 +29,7 @@ impl PlonkBn254Prover { } pub fn get_vkey_hash(build_dir: &Path) -> [u8; 32] { - let vkey_path = build_dir.join("vk.bin"); + let vkey_path = build_dir.join("plonk_vk.bin"); let vk_bin_bytes = std::fs::read(vkey_path).unwrap(); Sha256::digest(vk_bin_bytes).into() } @@ -72,7 +64,7 @@ impl PlonkBn254Prover { file.write_all(serialized.as_bytes()).unwrap(); // Write witness. - let witness_path = build_dir.join("witness.json"); + let witness_path = build_dir.join("plonk_witness.json"); let gnark_witness = GnarkWitness::new(witness); let mut file = File::create(witness_path).unwrap(); let serialized = serde_json::to_string(&gnark_witness).unwrap(); @@ -81,18 +73,14 @@ impl PlonkBn254Prover { build_plonk_bn254(build_dir.to_str().unwrap()); // Write the corresponding asset files to the build dir. - let sp1_verifier_path = build_dir.join("SP1Verifier.sol"); + let sp1_verifier_path = build_dir.join("SP1VerifierPlonk.sol"); let vkey_hash = Self::get_vkey_hash(&build_dir); let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt") .replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION) - .replace( - "{VERIFIER_HASH}", - format!("0x{}", hex::encode(vkey_hash)).as_str(), - ); + .replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str()) + .replace("{PROOF_SYSTEM}", "Plonk"); let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap(); - sp1_verifier_file - .write_all(sp1_verifier_str.as_bytes()) - .unwrap(); + sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap(); } /// Generates a PLONK proof given a witness. @@ -103,15 +91,14 @@ impl PlonkBn254Prover { let serialized = serde_json::to_string(&gnark_witness).unwrap(); witness_file.write_all(serialized.as_bytes()).unwrap(); - let mut proof = prove_plonk_bn254( - build_dir.to_str().unwrap(), - witness_file.path().to_str().unwrap(), - ); + let mut proof = + prove_plonk_bn254(build_dir.to_str().unwrap(), witness_file.path().to_str().unwrap()); proof.plonk_vkey_hash = Self::get_vkey_hash(&build_dir); proof } - /// Verify a PLONK proof and verify that the supplied vkey_hash and committed_values_digest match. + /// Verify a PLONK proof and verify that the supplied vkey_hash and committed_values_digest + /// match. pub fn verify( &self, proof: &PlonkBn254Proof, @@ -120,7 +107,9 @@ impl PlonkBn254Prover { build_dir: &Path, ) { if proof.plonk_vkey_hash != Self::get_vkey_hash(build_dir) { - panic!("Proof vkey hash does not match circuit vkey hash, it was generated with a different circuit."); + panic!( + "Proof vkey hash does not match circuit vkey hash, it was generated with a different circuit." + ); } verify_plonk_bn254( build_dir.to_str().unwrap(), diff --git a/crates/recursion/gnark-ffi/src/proof.rs b/crates/recursion/gnark-ffi/src/proof.rs new file mode 100644 index 0000000000..ab4345241a --- /dev/null +++ b/crates/recursion/gnark-ffi/src/proof.rs @@ -0,0 +1,26 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ProofBn254 { + Plonk(PlonkBn254Proof), + Groth16(Groth16Bn254Proof), +} + +/// A zero-knowledge proof generated by the PLONK protocol with a Base64 encoded gnark PLONK proof. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PlonkBn254Proof { + pub public_inputs: [String; 2], + pub encoded_proof: String, + pub raw_proof: String, + pub plonk_vkey_hash: [u8; 32], +} + +/// A zero-knowledge proof generated by the Groth16 protocol with a Base64 encoded gnark Groth16 +/// proof. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct Groth16Bn254Proof { + pub public_inputs: [String; 2], + pub encoded_proof: String, + pub raw_proof: String, + pub groth16_vkey_hash: [u8; 32], +} diff --git a/recursion/gnark-ffi/src/witness.rs b/crates/recursion/gnark-ffi/src/witness.rs similarity index 71% rename from recursion/gnark-ffi/src/witness.rs rename to crates/recursion/gnark-ffi/src/witness.rs index f4a2d6e69e..6dc45fb668 100644 --- a/recursion/gnark-ffi/src/witness.rs +++ b/crates/recursion/gnark-ffi/src/witness.rs @@ -1,13 +1,8 @@ -use std::fs::File; -use std::io::Write; +use std::{fs::File, io::Write}; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use p3_field::PrimeField; -use serde::Deserialize; -use serde::Serialize; -use sp1_recursion_compiler::ir::Config; -use sp1_recursion_compiler::ir::Witness; +use p3_field::{AbstractExtensionField, AbstractField, PrimeField}; +use serde::{Deserialize, Serialize}; +use sp1_recursion_compiler::ir::{Config, Witness}; /// A witness that can be used to initialize values for witness generation inside Gnark. #[derive(Debug, Clone, Default, Serialize, Deserialize)] @@ -26,11 +21,7 @@ impl GnarkWitness { witness.felts.push(C::F::from_canonical_usize(999)); witness.exts.push(C::EF::from_canonical_usize(999)); GnarkWitness { - vars: witness - .vars - .into_iter() - .map(|w| w.as_canonical_biguint().to_string()) - .collect(), + vars: witness.vars.into_iter().map(|w| w.as_canonical_biguint().to_string()).collect(), felts: witness .felts .into_iter() @@ -40,10 +31,7 @@ impl GnarkWitness { .exts .into_iter() .map(|w| { - w.as_base_slice() - .iter() - .map(|x| x.as_canonical_biguint().to_string()) - .collect() + w.as_base_slice().iter().map(|x| x.as_canonical_biguint().to_string()).collect() }) .collect(), vkey_hash: witness.vkey_hash.as_canonical_biguint().to_string(), diff --git a/recursion/program/CHANGELOG.md b/crates/recursion/program/CHANGELOG.md similarity index 100% rename from recursion/program/CHANGELOG.md rename to crates/recursion/program/CHANGELOG.md diff --git a/recursion/program/Cargo.toml b/crates/recursion/program/Cargo.toml similarity index 85% rename from recursion/program/Cargo.toml rename to crates/recursion/program/Cargo.toml index 134620d77f..ba8633caab 100644 --- a/recursion/program/Cargo.toml +++ b/crates/recursion/program/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-recursion-program" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." -readme = "../../README.md" +readme = "../../../README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -25,8 +25,10 @@ p3-merkle-tree = { workspace = true } p3-poseidon2 = { workspace = true } sp1-recursion-core = { workspace = true } sp1-recursion-compiler = { workspace = true } -sp1-core = { workspace = true } +sp1-core-machine = { workspace = true } sp1-primitives = { workspace = true } +sp1-stark = { workspace = true } +sp1-core-executor = { workspace = true } itertools = "0.13.0" serde = { version = "1.0.204", features = ["derive"] } rand = "0.8.5" @@ -34,4 +36,4 @@ tracing = "0.1.40" stacker = "0.1" [features] -debug = ["sp1-core/debug"] +debug = ["sp1-core-machine/debug"] diff --git a/recursion/program/src/challenger.rs b/crates/recursion/program/src/challenger.rs similarity index 91% rename from recursion/program/src/challenger.rs rename to crates/recursion/program/src/challenger.rs index d4632a6514..8a3732f47a 100644 --- a/recursion/program/src/challenger.rs +++ b/crates/recursion/program/src/challenger.rs @@ -1,14 +1,11 @@ use p3_field::AbstractField; -use sp1_recursion_compiler::prelude::MemIndex; -use sp1_recursion_compiler::prelude::MemVariable; -use sp1_recursion_compiler::prelude::Ptr; -use sp1_recursion_compiler::prelude::Variable; -use sp1_recursion_compiler::prelude::{Array, Builder, Config, DslVariable, Ext, Felt, Usize, Var}; -use sp1_recursion_core::runtime::HASH_RATE; -use sp1_recursion_core::runtime::{DIGEST_SIZE, PERMUTATION_WIDTH}; +use sp1_recursion_compiler::prelude::{ + Array, Builder, Config, DslVariable, Ext, Felt, MemIndex, MemVariable, Ptr, Usize, Var, + Variable, +}; +use sp1_recursion_core::runtime::{DIGEST_SIZE, HASH_RATE, PERMUTATION_WIDTH}; -use crate::fri::types::DigestVariable; -use crate::types::VerifyingKeyVariable; +use crate::{fri::types::DigestVariable, types::VerifyingKeyVariable}; /// Reference: [p3_challenger::CanObserve]. pub trait CanObserveVariable { @@ -155,11 +152,9 @@ impl DuplexChallengerVariable { builder.set(&mut self.input_buffer, self.nb_inputs, value); builder.assign(self.nb_inputs, self.nb_inputs + C::N::one()); - builder - .if_eq(self.nb_inputs, C::N::from_canonical_usize(HASH_RATE)) - .then(|builder| { - self.duplexing(builder); - }) + builder.if_eq(self.nb_inputs, C::N::from_canonical_usize(HASH_RATE)).then(|builder| { + self.duplexing(builder); + }) } fn observe_commitment(&mut self, builder: &mut Builder, commitment: DigestVariable) { @@ -296,20 +291,19 @@ impl FeltChallenger for DuplexChallengerVariable { #[cfg(test)] mod tests { - use p3_challenger::CanObserve; - use p3_challenger::CanSample; + use p3_challenger::{CanObserve, CanSample}; use p3_field::AbstractField; - use sp1_core::stark::StarkGenericConfig; - use sp1_core::utils::BabyBearPoseidon2; - use sp1_recursion_compiler::asm::AsmBuilder; - use sp1_recursion_compiler::asm::AsmConfig; - use sp1_recursion_compiler::ir::Felt; - use sp1_recursion_compiler::ir::Usize; - use sp1_recursion_compiler::ir::Var; - - use sp1_recursion_core::runtime::PERMUTATION_WIDTH; - use sp1_recursion_core::stark::utils::run_test_recursion; - use sp1_recursion_core::stark::utils::TestConfig; + + use sp1_recursion_compiler::{ + asm::{AsmBuilder, AsmConfig}, + ir::{Felt, Usize, Var}, + }; + + use sp1_recursion_core::{ + runtime::PERMUTATION_WIDTH, + stark::utils::{run_test_recursion, TestConfig}, + }; + use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; use crate::challenger::DuplexChallengerVariable; diff --git a/recursion/program/src/commit.rs b/crates/recursion/program/src/commit.rs similarity index 100% rename from recursion/program/src/commit.rs rename to crates/recursion/program/src/commit.rs diff --git a/recursion/program/src/constraints.rs b/crates/recursion/program/src/constraints.rs similarity index 82% rename from recursion/program/src/constraints.rs rename to crates/recursion/program/src/constraints.rs index ff71a2e641..3c92440992 100644 --- a/recursion/program/src/constraints.rs +++ b/crates/recursion/program/src/constraints.rs @@ -1,24 +1,21 @@ use p3_air::Air; use p3_commit::LagrangeSelectors; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use p3_field::TwoAdicField; -use sp1_core::air::MachineAir; -use sp1_core::stark::AirOpenedValues; -use sp1_core::stark::PROOF_MAX_NUM_PVS; -use sp1_core::stark::{MachineChip, StarkGenericConfig}; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Felt; -use sp1_recursion_compiler::prelude::Config; -use sp1_recursion_compiler::prelude::ExtConst; -use sp1_recursion_compiler::prelude::{Builder, Ext, SymbolicExt}; - -use crate::commit::PolynomialSpaceVariable; -use crate::fri::TwoAdicMultiplicativeCosetVariable; -use crate::stark::RecursiveVerifierConstraintFolder; -use crate::stark::StarkVerifier; -use crate::types::ChipOpenedValuesVariable; -use crate::types::ChipOpening; +use p3_field::{AbstractExtensionField, AbstractField, TwoAdicField}; + +use sp1_recursion_compiler::{ + ir::{Array, Felt}, + prelude::{Builder, Config, Ext, ExtConst, SymbolicExt}, +}; +use sp1_stark::{ + air::MachineAir, AirOpenedValues, MachineChip, StarkGenericConfig, PROOF_MAX_NUM_PVS, +}; + +use crate::{ + commit::PolynomialSpaceVariable, + fri::TwoAdicMultiplicativeCosetVariable, + stark::{RecursiveVerifierConstraintFolder, StarkVerifier}, + types::{ChipOpenedValuesVariable, ChipOpening}, +}; impl StarkVerifier where @@ -121,7 +118,7 @@ where ) } - /// Reference: [sp1_core::stark::Verifier::verify_constraints] + /// Reference: [sp1_core_machine::stark::Verifier::verify_constraints] pub fn verify_constraints( builder: &mut Builder, chip: &MachineChip, @@ -159,23 +156,19 @@ where mod tests { use itertools::{izip, Itertools}; use rand::{thread_rng, Rng}; - use sp1_core::stark::CpuProver; - use sp1_core::{ - io::SP1Stdin, - runtime::Program, - stark::{ - Chip, Com, Dom, OpeningProof, PcsProverData, RiscvAir, ShardCommitment, ShardProof, - StarkGenericConfig, StarkMachine, - }, - utils::{BabyBearPoseidon2, SP1CoreOpts}, - }; + use sp1_core_executor::Program; + use sp1_core_machine::{io::SP1Stdin, riscv::RiscvAir}; use sp1_recursion_core::stark::utils::{run_test_recursion, TestConfig}; use p3_challenger::{CanObserve, FieldChallenger}; use sp1_recursion_compiler::{asm::AsmBuilder, ir::Felt, prelude::ExtConst}; use p3_commit::{Pcs, PolynomialSpace}; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, Chip, Com, CpuProver, Dom, OpeningProof, + PcsProverData, SP1CoreOpts, ShardCommitment, ShardProof, StarkGenericConfig, StarkMachine, + }; use crate::stark::StarkVerifier; @@ -200,24 +193,15 @@ mod tests { PcsProverData: Send + Sync, SC::Val: p3_field::PrimeField32, { - let ShardProof { - commitment, - opened_values, - .. - } = proof; - - let ShardCommitment { - permutation_commit, - quotient_commit, - .. - } = commitment; + let ShardProof { commitment, opened_values, .. } = proof; + + let ShardCommitment { permutation_commit, quotient_commit, .. } = commitment; // Extract verification metadata. let pcs = machine.config().pcs(); - let permutation_challenges = (0..2) - .map(|_| challenger.sample_ext_element::()) - .collect::>(); + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext_element::()).collect::>(); challenger.observe(permutation_commit.clone()); @@ -228,20 +212,12 @@ mod tests { let zeta = challenger.sample_ext_element::(); - let chips = machine - .shard_chips_ordered(&proof.chip_ordering) - .collect::>(); + let chips = machine.shard_chips_ordered(&proof.chip_ordering).collect::>(); - let log_degrees = opened_values - .chips - .iter() - .map(|val| val.log_degree) - .collect::>(); + let log_degrees = opened_values.chips.iter().map(|val| val.log_degree).collect::>(); - let log_quotient_degrees = chips - .iter() - .map(|chip| chip.log_quotient_degree()) - .collect::>(); + let log_quotient_degrees = + chips.iter().map(|chip| chip.log_quotient_degree()).collect::>(); let trace_domains = log_degrees .iter() @@ -260,14 +236,7 @@ mod tests { }) .collect::>(); - ( - chips, - trace_domains, - quotient_chunk_domains, - permutation_challenges, - alpha, - zeta, - ) + (chips, trace_domains, quotient_chunk_domains, permutation_challenges, alpha, zeta) } #[test] @@ -278,14 +247,14 @@ mod tests { type A = RiscvAir; // Generate a dummy proof. - sp1_core::utils::setup_logger(); - let elf = include_bytes!("../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); + sp1_core_machine::utils::setup_logger(); + let elf = include_bytes!("../../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); let machine = A::machine(SC::default()); - let (_, vk) = machine.setup(&Program::from(elf)); + let (_, vk) = machine.setup(&Program::from(elf).unwrap()); let mut challenger = machine.config().challenger(); - let (proof, _, _) = sp1_core::utils::prove::<_, CpuProver<_, _>>( - Program::from(elf), + let (proof, _, _) = sp1_core_machine::utils::prove::<_, CpuProver<_, _>>( + Program::from(elf).unwrap(), &SP1Stdin::new(), SC::default(), SP1CoreOpts::default(), diff --git a/recursion/program/src/fri/domain.rs b/crates/recursion/program/src/fri/domain.rs similarity index 95% rename from recursion/program/src/fri/domain.rs rename to crates/recursion/program/src/fri/domain.rs index eca1a6e483..bb05f2a7cc 100644 --- a/recursion/program/src/fri/domain.rs +++ b/crates/recursion/program/src/fri/domain.rs @@ -159,17 +159,17 @@ where #[cfg(test)] pub(crate) mod tests { - use sp1_core::utils::inner_fri_config; use sp1_recursion_compiler::asm::AsmBuilder; use sp1_recursion_core::stark::utils::{run_test_recursion, TestConfig}; + use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, inner_fri_config, Dom, StarkGenericConfig, + }; use crate::utils::const_fri_config; use super::*; use p3_commit::{Pcs, PolynomialSpace}; use rand::{thread_rng, Rng}; - use sp1_core::stark::Dom; - use sp1_core::{stark::StarkGenericConfig, utils::BabyBearPoseidon2}; pub(crate) fn domain_assertions>( builder: &mut Builder, @@ -233,22 +233,12 @@ pub(crate) mod tests { let disjoint_domain_val = domain_val.create_disjoint_domain(1 << (log_d_val + log_quotient_degree)); let disjoint_domain = builder.constant(disjoint_domain_val); - domain_assertions( - &mut builder, - &disjoint_domain, - &disjoint_domain_val, - zeta_val, - ); + domain_assertions(&mut builder, &disjoint_domain, &disjoint_domain_val, zeta_val); let log_degree: Usize<_> = builder.eval(Usize::Const(log_d_val) + log_quotient_degree); let disjoint_domain_gen = domain.create_disjoint_domain(&mut builder, log_degree, Some(config_var.clone())); - domain_assertions( - &mut builder, - &disjoint_domain_gen, - &disjoint_domain_val, - zeta_val, - ); + domain_assertions(&mut builder, &disjoint_domain_gen, &disjoint_domain_val, zeta_val); // Now try splited domains let qc_domains_val = disjoint_domain_val.split_domains(1 << log_quotient_degree); diff --git a/recursion/program/src/fri/hints.rs b/crates/recursion/program/src/fri/hints.rs similarity index 88% rename from recursion/program/src/fri/hints.rs rename to crates/recursion/program/src/fri/hints.rs index 9b41276eee..081f7f4196 100644 --- a/recursion/program/src/fri/hints.rs +++ b/crates/recursion/program/src/fri/hints.rs @@ -1,21 +1,23 @@ -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use sp1_core::utils::{ - InnerBatchOpening, InnerChallenge, InnerCommitPhaseStep, InnerDigest, InnerFriProof, - InnerPcsProof, InnerQueryProof, InnerVal, -}; -use sp1_recursion_compiler::config::InnerConfig; +use p3_field::{AbstractExtensionField, AbstractField}; + use sp1_recursion_compiler::{ asm::AsmConfig, + config::InnerConfig, ir::{Array, Builder, Config}, }; use sp1_recursion_core::{air::Block, runtime::DIGEST_SIZE}; +use sp1_stark::{ + InnerBatchOpening, InnerChallenge, InnerCommitPhaseStep, InnerDigest, InnerFriProof, + InnerPcsProof, InnerQueryProof, InnerVal, +}; use super::types::{BatchOpeningVariable, TwoAdicPcsProofVariable}; -use crate::fri::types::{ - DigestVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, +use crate::{ + fri::types::{ + DigestVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, + }, + hints::Hintable, }; -use crate::hints::Hintable; type C = InnerConfig; @@ -66,10 +68,7 @@ impl Hintable for InnerCommitPhaseStep { fn read(builder: &mut Builder) -> Self::HintVariable { let sibling_value = builder.hint_ext(); let opening_proof = Vec::::read(builder); - Self::HintVariable { - sibling_value, - opening_proof, - } + Self::HintVariable { sibling_value, opening_proof } } fn write(&self) -> Vec::F>>> { @@ -118,17 +117,13 @@ impl Hintable for InnerQueryProof { fn read(builder: &mut Builder) -> Self::HintVariable { let commit_phase_openings = Vec::::read(builder); - Self::HintVariable { - commit_phase_openings, - } + Self::HintVariable { commit_phase_openings } } fn write(&self) -> Vec::F>>> { let mut stream = Vec::new(); - stream.extend(Vec::::write( - &self.commit_phase_openings, - )); + stream.extend(Vec::::write(&self.commit_phase_openings)); stream } @@ -170,23 +165,14 @@ impl Hintable for InnerFriProof { let query_proofs = Vec::::read(builder); let final_poly = builder.hint_ext(); let pow_witness = builder.hint_felt(); - Self::HintVariable { - commit_phase_commits, - query_proofs, - final_poly, - pow_witness, - } + Self::HintVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } } fn write(&self) -> Vec::F>>> { let mut stream = Vec::new(); stream.extend(Vec::::write( - &self - .commit_phase_commits - .iter() - .map(|x| (*x).into()) - .collect(), + &self.commit_phase_commits.iter().map(|x| (*x).into()).collect(), )); stream.extend(Vec::::write(&self.query_proofs)); let final_poly: &[InnerVal] = self.final_poly.as_base_slice(); @@ -205,10 +191,7 @@ impl Hintable for InnerBatchOpening { fn read(builder: &mut Builder) -> Self::HintVariable { let opened_values = Vec::>::read(builder); let opening_proof = Vec::::read(builder); - Self::HintVariable { - opened_values, - opening_proof, - } + Self::HintVariable { opened_values, opening_proof } } fn write(&self) -> Vec::F>>> { @@ -287,10 +270,7 @@ impl Hintable for InnerPcsProof { fn read(builder: &mut Builder) -> Self::HintVariable { let fri_proof = InnerFriProof::read(builder); let query_openings = Vec::>::read(builder); - Self::HintVariable { - fri_proof, - query_openings, - } + Self::HintVariable { fri_proof, query_openings } } fn write(&self) -> Vec::F>>> { diff --git a/recursion/program/src/fri/mod.rs b/crates/recursion/program/src/fri/mod.rs similarity index 58% rename from recursion/program/src/fri/mod.rs rename to crates/recursion/program/src/fri/mod.rs index a4e61590ec..b996b4f7b8 100644 --- a/recursion/program/src/fri/mod.rs +++ b/crates/recursion/program/src/fri/mod.rs @@ -5,34 +5,21 @@ pub mod types; pub use domain::*; use sp1_primitives::types::RecursionProgramType; -use sp1_recursion_compiler::ir::ExtensionOperand; -use sp1_recursion_compiler::ir::Ptr; +use sp1_recursion_compiler::ir::{ExtensionOperand, Ptr}; use sp1_recursion_core::runtime::DIGEST_SIZE; pub use two_adic_pcs::*; -use p3_field::AbstractField; -use p3_field::Field; -use p3_field::TwoAdicField; - -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Builder; -use sp1_recursion_compiler::ir::Config; -use sp1_recursion_compiler::ir::Ext; -use sp1_recursion_compiler::ir::Felt; -use sp1_recursion_compiler::ir::SymbolicVar; -use sp1_recursion_compiler::ir::Usize; -use sp1_recursion_compiler::ir::Var; - -use self::types::DigestVariable; -use self::types::DimensionsVariable; -use self::types::FriChallengesVariable; -use self::types::FriConfigVariable; -use self::types::FriProofVariable; -use self::types::FriQueryProofVariable; -use crate::challenger::CanObserveVariable; -use crate::challenger::CanSampleBitsVariable; -use crate::challenger::DuplexChallengerVariable; -use crate::challenger::FeltChallenger; +use p3_field::{AbstractField, Field, TwoAdicField}; + +use sp1_recursion_compiler::ir::{Array, Builder, Config, Ext, Felt, SymbolicVar, Usize, Var}; + +use self::types::{ + DigestVariable, DimensionsVariable, FriChallengesVariable, FriConfigVariable, FriProofVariable, + FriQueryProofVariable, +}; +use crate::challenger::{ + CanObserveVariable, CanSampleBitsVariable, DuplexChallengerVariable, FeltChallenger, +}; /// Reference: https://github.com/Plonky3/Plonky3/blob/4809fa7bedd9ba8f6f5d3267b1592618e3776c57/fri/src/verifier.rs#L27 pub fn verify_shape_and_sample_challenges( @@ -43,25 +30,21 @@ pub fn verify_shape_and_sample_challenges( ) -> FriChallengesVariable { let mut betas: Array> = builder.dyn_array(proof.commit_phase_commits.len()); - builder - .range(0, proof.commit_phase_commits.len()) - .for_each(|i, builder| { - let comm = builder.get(&proof.commit_phase_commits, i); - challenger.observe(builder, comm); - let sample = challenger.sample_ext(builder); - builder.set(&mut betas, i, sample); - }); + builder.range(0, proof.commit_phase_commits.len()).for_each(|i, builder| { + let comm = builder.get(&proof.commit_phase_commits, i); + challenger.observe(builder, comm); + let sample = challenger.sample_ext(builder); + builder.set(&mut betas, i, sample); + }); // Observe the final polynomial. let final_poly_felts = builder.ext2felt(proof.final_poly); challenger.observe_slice(builder, final_poly_felts); let num_query_proofs = proof.query_proofs.len().materialize(builder); - builder - .if_ne(num_query_proofs, config.num_queries) - .then(|builder| { - builder.error(); - }); + builder.if_ne(num_query_proofs, config.num_queries).then(|builder| { + builder.error(); + }); challenger.check_witness(builder, config.proof_of_work_bits, proof.pow_witness); @@ -73,10 +56,7 @@ pub fn verify_shape_and_sample_challenges( builder.set(&mut query_indices, i, index_bits); }); - FriChallengesVariable { - query_indices, - betas, - } + FriChallengesVariable { query_indices, betas } } /// Verifies a set of FRI challenges. @@ -95,26 +75,24 @@ pub fn verify_challenges( { let nb_commit_phase_commits = proof.commit_phase_commits.len().materialize(builder); let log_max_height = builder.eval(nb_commit_phase_commits + config.log_blowup); - builder - .range(0, challenges.query_indices.len()) - .for_each(|i, builder| { - let index_bits = builder.get(&challenges.query_indices, i); - let query_proof = builder.get(&proof.query_proofs, i); - let ro = builder.get(reduced_openings, i); - - let folded_eval = verify_query( - builder, - config, - &proof.commit_phase_commits, - &index_bits, - &query_proof, - &challenges.betas, - &ro, - Usize::Var(log_max_height), - ); - - builder.assert_ext_eq(folded_eval, proof.final_poly); - }); + builder.range(0, challenges.query_indices.len()).for_each(|i, builder| { + let index_bits = builder.get(&challenges.query_indices, i); + let query_proof = builder.get(&proof.query_proofs, i); + let ro = builder.get(reduced_openings, i); + + let folded_eval = verify_query( + builder, + config, + &proof.commit_phase_commits, + &index_bits, + &query_proof, + &challenges.betas, + &ro, + Usize::Var(log_max_height), + ); + + builder.assert_ext_eq(folded_eval, proof.final_poly); + }); } /// Verifies a FRI query. @@ -149,69 +127,62 @@ where }; let log_max_height = log_max_height.materialize(builder); - builder - .range(0, commit_phase_commits.len()) - .for_each(|i, builder| { - let log_folded_height: Var<_> = builder.eval(log_max_height - i - C::N::one()); - let log_folded_height_plus_one: Var<_> = builder.eval(log_folded_height + C::N::one()); - let commit = builder.get(commit_phase_commits, i); - let step = builder.get(&proof.commit_phase_openings, i); - let beta = builder.get(betas, i); - - let reduced_opening = builder.get(reduced_openings, log_folded_height_plus_one); - builder.assign(folded_eval, folded_eval + reduced_opening); - - let index_bit = builder.get(index_bits, i); - let index_sibling_mod_2: Var = - builder.eval(SymbolicVar::from(C::N::one()) - index_bit); - let i_plus_one = builder.eval(i + C::N::one()); - let index_pair = index_bits.shift(builder, i_plus_one); - - let mut evals: Array> = builder.array(2); - builder.set_value(&mut evals, 0, folded_eval); - builder.set_value(&mut evals, 1, folded_eval); - builder.set_value(&mut evals, index_sibling_mod_2, step.sibling_value); - - let dims = DimensionsVariable:: { - height: builder.sll(C::N::one(), Usize::Var(log_folded_height)), - }; - let mut dims_slice: Array> = builder.array(1); - builder.set_value(&mut dims_slice, 0, dims); - - let mut opened_values = builder.array(1); - builder.set_value(&mut opened_values, 0, evals.clone()); - verify_batch::( - builder, - &commit, - dims_slice, - index_pair, - opened_values, - &step.opening_proof, - ); - - let two_adic_generator_one = config.get_two_adic_generator(builder, Usize::Const(1)); - let xs_0: Ext<_, _> = builder.eval(x); - let xs_1: Ext<_, _> = builder.eval(x); - builder - .if_eq(index_sibling_mod_2, C::N::zero()) - .then_or_else( - |builder| { - builder.assign(xs_0, x * two_adic_generator_one.to_operand().symbolic()); - }, - |builder| { - builder.assign(xs_1, x * two_adic_generator_one.to_operand().symbolic()); - }, - ); + builder.range(0, commit_phase_commits.len()).for_each(|i, builder| { + let log_folded_height: Var<_> = builder.eval(log_max_height - i - C::N::one()); + let log_folded_height_plus_one: Var<_> = builder.eval(log_folded_height + C::N::one()); + let commit = builder.get(commit_phase_commits, i); + let step = builder.get(&proof.commit_phase_openings, i); + let beta = builder.get(betas, i); + + let reduced_opening = builder.get(reduced_openings, log_folded_height_plus_one); + builder.assign(folded_eval, folded_eval + reduced_opening); + + let index_bit = builder.get(index_bits, i); + let index_sibling_mod_2: Var = + builder.eval(SymbolicVar::from(C::N::one()) - index_bit); + let i_plus_one = builder.eval(i + C::N::one()); + let index_pair = index_bits.shift(builder, i_plus_one); + + let mut evals: Array> = builder.array(2); + builder.set_value(&mut evals, 0, folded_eval); + builder.set_value(&mut evals, 1, folded_eval); + builder.set_value(&mut evals, index_sibling_mod_2, step.sibling_value); + + let dims = DimensionsVariable:: { + height: builder.sll(C::N::one(), Usize::Var(log_folded_height)), + }; + let mut dims_slice: Array> = builder.array(1); + builder.set_value(&mut dims_slice, 0, dims); + + let mut opened_values = builder.array(1); + builder.set_value(&mut opened_values, 0, evals.clone()); + verify_batch::( + builder, + &commit, + dims_slice, + index_pair, + opened_values, + &step.opening_proof, + ); + + let two_adic_generator_one = config.get_two_adic_generator(builder, Usize::Const(1)); + let xs_0: Ext<_, _> = builder.eval(x); + let xs_1: Ext<_, _> = builder.eval(x); + builder.if_eq(index_sibling_mod_2, C::N::zero()).then_or_else( + |builder| { + builder.assign(xs_0, x * two_adic_generator_one.to_operand().symbolic()); + }, + |builder| { + builder.assign(xs_1, x * two_adic_generator_one.to_operand().symbolic()); + }, + ); - let eval_0 = builder.get(&evals, 0); - let eval_1 = builder.get(&evals, 1); - builder.assign( - folded_eval, - eval_0 + (beta - xs_0) * (eval_1 - eval_0) / (xs_1 - xs_0), - ); + let eval_0 = builder.get(&evals, 0); + let eval_1 = builder.get(&evals, 1); + builder.assign(folded_eval, eval_0 + (beta - xs_0) * (eval_1 - eval_0) / (xs_1 - xs_0)); - builder.assign(x, x * x); - }); + builder.assign(x, x * x); + }); builder.cycle_tracker("verify-query"); folded_eval @@ -313,21 +284,15 @@ pub fn reduce_fast( let mut nested_opened_values: Array<_, Array<_, Ext<_, _>>> = builder.dyn_array(8192); let start_dim_idx: Var<_> = builder.eval(dim_idx); builder.cycle_tracker("verify-batch-reduce-fast-setup"); - builder - .range(start_dim_idx, dims.len()) - .for_each(|i, builder| { - let height = builder.get(dims, i).height; - builder.if_eq(height, curr_height_padded).then(|builder| { - let opened_values = builder.get(opened_values, i); - builder.set_value( - &mut nested_opened_values, - nb_opened_values, - opened_values.clone(), - ); - builder.assign(nb_opened_values, nb_opened_values + C::N::one()); - builder.assign(dim_idx, dim_idx + C::N::one()); - }); + builder.range(start_dim_idx, dims.len()).for_each(|i, builder| { + let height = builder.get(dims, i).height; + builder.if_eq(height, curr_height_padded).then(|builder| { + let opened_values = builder.get(opened_values, i); + builder.set_value(&mut nested_opened_values, nb_opened_values, opened_values.clone()); + builder.assign(nb_opened_values, nb_opened_values + C::N::one()); + builder.assign(dim_idx, dim_idx + C::N::one()); }); + }); builder.cycle_tracker("verify-batch-reduce-fast-setup"); let h = if D == 1 { diff --git a/recursion/program/src/fri/two_adic_pcs.rs b/crates/recursion/program/src/fri/two_adic_pcs.rs similarity index 52% rename from recursion/program/src/fri/two_adic_pcs.rs rename to crates/recursion/program/src/fri/two_adic_pcs.rs index 24200696c3..10f49aba42 100644 --- a/recursion/program/src/fri/two_adic_pcs.rs +++ b/crates/recursion/program/src/fri/two_adic_pcs.rs @@ -1,24 +1,22 @@ use p3_commit::TwoAdicMultiplicativeCoset; -use p3_field::AbstractField; -use p3_field::TwoAdicField; +use p3_field::{AbstractField, TwoAdicField}; use p3_symmetric::Hash; use sp1_primitives::types::RecursionProgramType; use sp1_recursion_compiler::prelude::*; use sp1_recursion_core::runtime::DIGEST_SIZE; -use super::types::DigestVariable; -use super::types::DimensionsVariable; -use super::types::FriConfigVariable; -use super::types::TwoAdicPcsMatsVariable; -use super::types::TwoAdicPcsProofVariable; -use super::types::TwoAdicPcsRoundVariable; use super::{ + types::{ + DigestVariable, DimensionsVariable, FriConfigVariable, TwoAdicPcsMatsVariable, + TwoAdicPcsProofVariable, TwoAdicPcsRoundVariable, + }, verify_batch, verify_challenges, verify_shape_and_sample_challenges, TwoAdicMultiplicativeCosetVariable, }; -use crate::challenger::DuplexChallengerVariable; -use crate::challenger::FeltChallenger; -use crate::commit::PcsVariable; +use crate::{ + challenger::{DuplexChallengerVariable, FeltChallenger}, + commit::PcsVariable, +}; pub fn verify_two_adic_pcs( builder: &mut Builder, @@ -42,137 +40,120 @@ pub fn verify_two_adic_pcs( verify_shape_and_sample_challenges(builder, config, &proof.fri_proof, challenger); builder.cycle_tracker("stage-d-1-verify-shape-and-sample-challenges"); - let commit_phase_commits_len = proof - .fri_proof - .commit_phase_commits - .len() - .materialize(builder); + let commit_phase_commits_len = proof.fri_proof.commit_phase_commits.len().materialize(builder); let log_global_max_height: Var<_> = builder.eval(commit_phase_commits_len + log_blowup); let mut reduced_openings: Array>> = builder.array(proof.query_openings.len()); builder.cycle_tracker("stage-d-2-fri-fold"); - builder - .range(0, proof.query_openings.len()) - .for_each(|i, builder| { - let query_opening = builder.get(&proof.query_openings, i); - let index_bits = builder.get(&fri_challenges.query_indices, i); - - let mut ro: Array> = builder.array(32); - let mut alpha_pow: Array> = builder.array(32); - let zero_ef = builder.eval(C::EF::zero().cons()); - for j in 0..32 { - builder.set_value(&mut ro, j, zero_ef); - } - let one_ef = builder.eval(C::EF::one().cons()); - for j in 0..32 { - builder.set_value(&mut alpha_pow, j, one_ef); - } + builder.range(0, proof.query_openings.len()).for_each(|i, builder| { + let query_opening = builder.get(&proof.query_openings, i); + let index_bits = builder.get(&fri_challenges.query_indices, i); + + let mut ro: Array> = builder.array(32); + let mut alpha_pow: Array> = builder.array(32); + let zero_ef = builder.eval(C::EF::zero().cons()); + for j in 0..32 { + builder.set_value(&mut ro, j, zero_ef); + } + let one_ef = builder.eval(C::EF::one().cons()); + for j in 0..32 { + builder.set_value(&mut alpha_pow, j, one_ef); + } - builder.range(0, rounds.len()).for_each(|j, builder| { - let batch_opening = builder.get(&query_opening, j); - let round = builder.get(&rounds, j); - let batch_commit = round.batch_commit; - let mats = round.mats; - - let mut batch_heights_log2: Array> = builder.array(mats.len()); - builder.range(0, mats.len()).for_each(|k, builder| { - let mat = builder.get(&mats, k); - let height_log2: Var<_> = builder.eval(mat.domain.log_n + log_blowup); - builder.set_value(&mut batch_heights_log2, k, height_log2); - }); - let mut batch_dims: Array> = builder.array(mats.len()); - builder.range(0, mats.len()).for_each(|k, builder| { - let mat = builder.get(&mats, k); - let dim = DimensionsVariable:: { - height: builder.eval(mat.domain.size() * blowup), + builder.range(0, rounds.len()).for_each(|j, builder| { + let batch_opening = builder.get(&query_opening, j); + let round = builder.get(&rounds, j); + let batch_commit = round.batch_commit; + let mats = round.mats; + + let mut batch_heights_log2: Array> = builder.array(mats.len()); + builder.range(0, mats.len()).for_each(|k, builder| { + let mat = builder.get(&mats, k); + let height_log2: Var<_> = builder.eval(mat.domain.log_n + log_blowup); + builder.set_value(&mut batch_heights_log2, k, height_log2); + }); + let mut batch_dims: Array> = builder.array(mats.len()); + builder.range(0, mats.len()).for_each(|k, builder| { + let mat = builder.get(&mats, k); + let dim = + DimensionsVariable:: { height: builder.eval(mat.domain.size() * blowup) }; + builder.set_value(&mut batch_dims, k, dim); + }); + + let log_batch_max_height = builder.get(&batch_heights_log2, 0); + let bits_reduced: Var<_> = builder.eval(log_global_max_height - log_batch_max_height); + let index_bits_shifted_v1 = index_bits.shift(builder, bits_reduced); + verify_batch::( + builder, + &batch_commit, + batch_dims, + index_bits_shifted_v1, + batch_opening.opened_values.clone(), + &batch_opening.opening_proof, + ); + + builder.range(0, batch_opening.opened_values.len()).for_each(|k, builder| { + let mat_opening = builder.get(&batch_opening.opened_values, k); + let mat = builder.get(&mats, k); + let mat_points = mat.points; + let mat_values = mat.values; + + let log2_domain_size = mat.domain.log_n; + let log_height: Var = builder.eval(log2_domain_size + log_blowup); + + let bits_reduced: Var = builder.eval(log_global_max_height - log_height); + let index_bits_shifted = index_bits.shift(builder, bits_reduced); + + let two_adic_generator = config.get_two_adic_generator(builder, log_height); + builder.cycle_tracker("exp_reverse_bits_len"); + + let two_adic_generator_exp: Felt = + if matches!(builder.program_type, RecursionProgramType::Wrap) { + builder.exp_reverse_bits_len( + two_adic_generator, + &index_bits_shifted, + log_height, + ) + } else { + builder.exp_reverse_bits_len_fast( + two_adic_generator, + &index_bits_shifted, + log_height, + ) }; - builder.set_value(&mut batch_dims, k, dim); - }); - let log_batch_max_height = builder.get(&batch_heights_log2, 0); - let bits_reduced: Var<_> = - builder.eval(log_global_max_height - log_batch_max_height); - let index_bits_shifted_v1 = index_bits.shift(builder, bits_reduced); - verify_batch::( - builder, - &batch_commit, - batch_dims, - index_bits_shifted_v1, - batch_opening.opened_values.clone(), - &batch_opening.opening_proof, - ); + builder.cycle_tracker("exp_reverse_bits_len"); + let x: Felt = builder.eval(two_adic_generator_exp * g); + + builder.range(0, mat_points.len()).for_each(|l, builder| { + let z: Ext = builder.get(&mat_points, l); + let ps_at_z = builder.get(&mat_values, l); + let input = FriFoldInput { + z, + alpha, + x, + log_height, + mat_opening: mat_opening.clone(), + ps_at_z: ps_at_z.clone(), + alpha_pow: alpha_pow.clone(), + ro: ro.clone(), + }; + builder.set_value(&mut input_ptr, 0, input); - builder - .range(0, batch_opening.opened_values.len()) - .for_each(|k, builder| { - let mat_opening = builder.get(&batch_opening.opened_values, k); - let mat = builder.get(&mats, k); - let mat_points = mat.points; - let mat_values = mat.values; - - let log2_domain_size = mat.domain.log_n; - let log_height: Var = builder.eval(log2_domain_size + log_blowup); - - let bits_reduced: Var = - builder.eval(log_global_max_height - log_height); - let index_bits_shifted = index_bits.shift(builder, bits_reduced); - - let two_adic_generator = config.get_two_adic_generator(builder, log_height); - builder.cycle_tracker("exp_reverse_bits_len"); - - let two_adic_generator_exp: Felt = - if matches!(builder.program_type, RecursionProgramType::Wrap) { - builder.exp_reverse_bits_len( - two_adic_generator, - &index_bits_shifted, - log_height, - ) - } else { - builder.exp_reverse_bits_len_fast( - two_adic_generator, - &index_bits_shifted, - log_height, - ) - }; - - builder.cycle_tracker("exp_reverse_bits_len"); - let x: Felt = builder.eval(two_adic_generator_exp * g); - - builder.range(0, mat_points.len()).for_each(|l, builder| { - let z: Ext = builder.get(&mat_points, l); - let ps_at_z = builder.get(&mat_values, l); - let input = FriFoldInput { - z, - alpha, - x, - log_height, - mat_opening: mat_opening.clone(), - ps_at_z: ps_at_z.clone(), - alpha_pow: alpha_pow.clone(), - ro: ro.clone(), - }; - builder.set_value(&mut input_ptr, 0, input); - - let ps_at_z_len = ps_at_z.len().materialize(builder); - builder.push(DslIr::FriFold(ps_at_z_len, input_ptr.clone())); - }); - }); + let ps_at_z_len = ps_at_z.len().materialize(builder); + builder.push(DslIr::FriFold(ps_at_z_len, input_ptr.clone())); + }); }); - - builder.set_value(&mut reduced_openings, i, ro); }); + + builder.set_value(&mut reduced_openings, i, ro); + }); builder.cycle_tracker("stage-d-2-fri-fold"); builder.cycle_tracker("stage-d-3-verify-challenges"); - verify_challenges( - builder, - config, - &proof.fri_proof, - &fri_challenges, - &reduced_openings, - ); + verify_challenges(builder, config, &proof.fri_proof, &fri_challenges, &reduced_openings); builder.cycle_tracker("stage-d-3-verify-challenges"); } @@ -218,18 +199,11 @@ where builder.set_value(&mut values, j, tmp); } - let mat = TwoAdicPcsMatsVariable { - domain, - points, - values, - }; + let mat = TwoAdicPcsMatsVariable { domain, points, values }; builder.set_value(&mut mats, i, mat); } - Self { - batch_commit: commit, - mats, - } + Self { batch_commit: commit, mats } } } @@ -270,46 +244,38 @@ where pub mod tests { - use std::cmp::Reverse; - use std::collections::VecDeque; - - use crate::challenger::CanObserveVariable; - use crate::challenger::DuplexChallengerVariable; - use crate::challenger::FeltChallenger; - use crate::commit::PcsVariable; - use crate::fri::types::TwoAdicPcsRoundVariable; - use crate::fri::TwoAdicFriPcsVariable; - use crate::fri::TwoAdicMultiplicativeCosetVariable; - use crate::hints::Hintable; - use crate::utils::const_fri_config; + use std::{cmp::Reverse, collections::VecDeque}; + + use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable, FeltChallenger}, + commit::PcsVariable, + fri::{ + types::TwoAdicPcsRoundVariable, TwoAdicFriPcsVariable, + TwoAdicMultiplicativeCosetVariable, + }, + hints::Hintable, + utils::const_fri_config, + }; use itertools::Itertools; use p3_baby_bear::BabyBear; - use p3_challenger::CanObserve; - use p3_challenger::FieldChallenger; - use p3_commit::Pcs; - use p3_commit::TwoAdicMultiplicativeCoset; + use p3_challenger::{CanObserve, FieldChallenger}; + use p3_commit::{Pcs, TwoAdicMultiplicativeCoset}; use p3_field::AbstractField; use p3_matrix::dense::RowMajorMatrix; use rand::rngs::OsRng; - use sp1_core::utils::baby_bear_poseidon2::compressed_fri_config; - use sp1_core::utils::inner_perm; - use sp1_core::utils::InnerChallenge; - use sp1_core::utils::InnerChallenger; - use sp1_core::utils::InnerCompress; - use sp1_core::utils::InnerDft; - use sp1_core::utils::InnerHash; - use sp1_core::utils::InnerPcs; - use sp1_core::utils::InnerPcsProof; - use sp1_core::utils::InnerVal; - use sp1_core::utils::InnerValMmcs; - use sp1_recursion_compiler::config::InnerConfig; - use sp1_recursion_compiler::ir::Array; - use sp1_recursion_compiler::ir::Builder; - use sp1_recursion_compiler::ir::Usize; - use sp1_recursion_compiler::ir::Var; - use sp1_recursion_core::air::Block; - use sp1_recursion_core::runtime::RecursionProgram; - use sp1_recursion_core::runtime::DIGEST_SIZE; + + use sp1_recursion_compiler::{ + config::InnerConfig, + ir::{Array, Builder, Usize, Var}, + }; + use sp1_recursion_core::{ + air::Block, + runtime::{RecursionProgram, DIGEST_SIZE}, + }; + use sp1_stark::{ + baby_bear_poseidon2::compressed_fri_config, inner_perm, InnerChallenge, InnerChallenger, + InnerCompress, InnerDft, InnerHash, InnerPcs, InnerPcsProof, InnerVal, InnerValMmcs, + }; pub fn build_test_fri_with_cols_and_log2_rows( nb_cols: usize, @@ -323,12 +289,8 @@ pub mod tests { let compress = InnerCompress::new(perm.clone()); let val_mmcs = InnerValMmcs::new(hash, compress); let dft = InnerDft {}; - let pcs_val: InnerPcs = InnerPcs::new( - log_degrees.iter().copied().max().unwrap(), - dft, - val_mmcs, - fri_config, - ); + let pcs_val: InnerPcs = + InnerPcs::new(log_degrees.iter().copied().max().unwrap(), dft, val_mmcs, fri_config); // Generate proof. let domains_and_polys = log_degrees @@ -351,10 +313,7 @@ pub mod tests { let mut challenger = InnerChallenger::new(perm.clone()); challenger.observe(commit); let zeta = challenger.sample_ext_element::(); - let points = domains_and_polys - .iter() - .map(|_| vec![zeta]) - .collect::>(); + let points = domains_and_polys.iter().map(|_| vec![zeta]).collect::>(); let (opening, proof) = pcs_val.open(vec![(&data, points)], &mut challenger); // Verify proof. @@ -369,9 +328,7 @@ pub mod tests { .zip(&opening[0]) .map(|((domain, _), mat_openings)| (*domain, vec![(zeta, mat_openings[0].clone())])) .collect(); - pcs_val - .verify(vec![(commit, os.clone())], &proof, &mut challenger) - .unwrap(); + pcs_val.verify(vec![(commit, os.clone())], &proof, &mut challenger).unwrap(); // Test the recursive Pcs. let mut builder = Builder::::default(); diff --git a/recursion/program/src/fri/types.rs b/crates/recursion/program/src/fri/types.rs similarity index 100% rename from recursion/program/src/fri/types.rs rename to crates/recursion/program/src/fri/types.rs diff --git a/recursion/program/src/hints.rs b/crates/recursion/program/src/hints.rs similarity index 87% rename from recursion/program/src/hints.rs rename to crates/recursion/program/src/hints.rs index 0163b0380d..41ff6e46b5 100644 --- a/recursion/program/src/hints.rs +++ b/crates/recursion/program/src/hints.rs @@ -1,37 +1,37 @@ use p3_baby_bear::BabyBear; use p3_challenger::DuplexChallenger; use p3_commit::TwoAdicMultiplicativeCoset; -use p3_field::TwoAdicField; -use p3_field::{AbstractExtensionField, AbstractField}; -use sp1_core::air::{MachineAir, Word, PV_DIGEST_NUM_WORDS}; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::stark::{ - AirOpenedValues, ChipOpenedValues, Com, RiscvAir, ShardCommitment, ShardOpenedValues, -}; -use sp1_core::utils::{ - BabyBearPoseidon2, InnerChallenge, InnerDigest, InnerDigestHash, InnerPcsProof, InnerPerm, - InnerVal, -}; +use p3_field::{AbstractExtensionField, AbstractField, TwoAdicField}; + +use sp1_core_machine::riscv::RiscvAir; use sp1_recursion_compiler::{ config::InnerConfig, - ir::{Array, Builder, Config, Ext, Felt, MemVariable, Var}, + ir::{Array, Builder, Config, Ext, Felt, MemVariable, Var, Variable}, }; -use sp1_recursion_core::air::Block; -use sp1_recursion_core::runtime::PERMUTATION_WIDTH; - -use crate::challenger::DuplexChallengerVariable; -use crate::fri::TwoAdicMultiplicativeCosetVariable; -use crate::machine::*; -use crate::stark::{ShardProofHint, VerifyingKeyHint}; -use crate::types::{ - AirOpenedValuesVariable, ChipOpenedValuesVariable, Sha256DigestVariable, - ShardCommitmentVariable, ShardOpenedValuesVariable, ShardProofVariable, VerifyingKeyVariable, +use sp1_recursion_core::{air::Block, runtime::PERMUTATION_WIDTH}; +use sp1_stark::{ + air::{MachineAir, PV_DIGEST_NUM_WORDS}, + baby_bear_poseidon2::BabyBearPoseidon2, + AirOpenedValues, ChipOpenedValues, Com, InnerChallenge, InnerDigest, InnerDigestHash, + InnerPcsProof, InnerPerm, InnerVal, ShardCommitment, ShardOpenedValues, StarkGenericConfig, + Word, +}; + +use crate::{ + challenger::DuplexChallengerVariable, + fri::TwoAdicMultiplicativeCosetVariable, + machine::*, + stark::{ShardProofHint, VerifyingKeyHint}, + types::{ + AirOpenedValuesVariable, ChipOpenedValuesVariable, QuotientData, QuotientDataValues, + Sha256DigestVariable, ShardCommitmentVariable, ShardOpenedValuesVariable, + ShardProofVariable, VerifyingKeyVariable, + }, + utils::{get_chip_quotient_data, get_preprocessed_data, get_sorted_indices}, }; -use crate::types::{QuotientData, QuotientDataValues}; -use crate::utils::{get_chip_quotient_data, get_preprocessed_data, get_sorted_indices}; pub trait Hintable { - type HintVariable: MemVariable; + type HintVariable: Variable; fn read(builder: &mut Builder) -> Self::HintVariable; @@ -90,10 +90,7 @@ impl Hintable for [Word; PV_DIGEST_NUM_WORDS] { } fn write(&self) -> Vec::F>>> { - vec![self - .iter() - .flat_map(|w| w.0.iter().map(|f| Block::from(*f))) - .collect::>()] + vec![self.iter().flat_map(|w| w.0.iter().map(|f| Block::from(*f))).collect::>()] } } @@ -104,10 +101,7 @@ impl Hintable for QuotientDataValues { let log_quotient_degree = usize::read(builder); let quotient_size = usize::read(builder); - QuotientData { - log_quotient_degree, - quotient_size, - } + QuotientData { log_quotient_degree, quotient_size } } fn write(&self) -> Vec::F>>> { @@ -129,12 +123,7 @@ impl Hintable for TwoAdicMultiplicativeCoset { let size = usize::read(builder); // Initialize a domain. - TwoAdicMultiplicativeCosetVariable:: { - log_n, - size, - shift, - g: g_val, - } + TwoAdicMultiplicativeCosetVariable:: { log_n, size, shift, g: g_val } } fn write(&self) -> Vec::F>>> { @@ -170,7 +159,10 @@ impl> Hintable for &H { } } -impl> Hintable for Vec { +impl> Hintable for Vec +where + >::HintVariable: MemVariable, +{ type HintVariable = Array; fn read(builder: &mut Builder) -> Self::HintVariable { @@ -206,10 +198,7 @@ impl Hintable for Vec { } fn write(&self) -> Vec>> { - vec![self - .iter() - .map(|x| Block::from(InnerVal::from_canonical_usize(*x))) - .collect()] + vec![self.iter().map(|x| Block::from(InnerVal::from_canonical_usize(*x))).collect()] } } @@ -233,10 +222,7 @@ impl Hintable for Vec { } fn write(&self) -> Vec::F>>> { - vec![self - .iter() - .map(|x| Block::from((*x).as_base_slice())) - .collect()] + vec![self.iter().map(|x| Block::from((*x).as_base_slice())).collect()] } } @@ -367,11 +353,7 @@ impl Hintable for ShardCommitment { let main_commit = InnerDigest::read(builder); let permutation_commit = InnerDigest::read(builder); let quotient_commit = InnerDigest::read(builder); - ShardCommitmentVariable { - main_commit, - permutation_commit, - quotient_commit, - } + ShardCommitmentVariable { main_commit, permutation_commit, quotient_commit } } fn write(&self) -> Vec::F>>> { @@ -436,12 +418,7 @@ impl< let pc_start = InnerVal::read(builder); let preprocessed_sorted_idxs = Vec::::read(builder); let prep_domains = Vec::>::read(builder); - VerifyingKeyVariable { - commitment, - pc_start, - preprocessed_sorted_idxs, - prep_domains, - } + VerifyingKeyVariable { commitment, pc_start, preprocessed_sorted_idxs, prep_domains } } fn write(&self) -> Vec::F>>> { @@ -493,15 +470,15 @@ where let quotient_data = get_chip_quotient_data(self.machine, self.proof); let sorted_indices = get_sorted_indices(self.machine, self.proof); - let mut stream = Vec::new(); - stream.extend(self.proof.commitment.write()); - stream.extend(self.proof.opened_values.write()); - stream.extend(self.proof.opening_proof.write()); - stream.extend(self.proof.public_values.write()); - stream.extend(quotient_data.write()); - stream.extend(sorted_indices.write()); - - stream + [ + self.proof.commitment.write(), + self.proof.opened_values.write(), + self.proof.opening_proof.write(), + self.proof.public_values.write(), + quotient_data.write(), + sorted_indices.write(), + ] + .concat() } } @@ -559,12 +536,7 @@ impl<'a, A: MachineAir> Hintable let kinds = Vec::::read(builder); let is_complete = builder.hint_var(); - SP1CompressMemoryLayoutVariable { - compress_vk, - shard_proofs, - kinds, - is_complete, - } + SP1CompressMemoryLayoutVariable { compress_vk, shard_proofs, kinds, is_complete } } fn write(&self) -> Vec::F>>> { @@ -667,11 +639,8 @@ impl<'a, A: MachineAir> Hintable .map(|proof| ShardProofHint::::new(self.machine, proof)) .collect::>(); - let committed_value_digest = self - .committed_value_digest - .iter() - .map(|w| w.0.to_vec()) - .collect::>(); + let committed_value_digest = + self.committed_value_digest.iter().map(|w| w.0.to_vec()).collect::>(); stream.extend(compress_vk_hint.write()); stream.extend(proof_hints.write()); diff --git a/recursion/program/src/lib.rs b/crates/recursion/program/src/lib.rs similarity index 100% rename from recursion/program/src/lib.rs rename to crates/recursion/program/src/lib.rs diff --git a/recursion/program/src/machine/compress.rs b/crates/recursion/program/src/machine/compress.rs similarity index 86% rename from recursion/program/src/machine/compress.rs rename to crates/recursion/program/src/machine/compress.rs index 353b6e2fd8..75b57378ac 100644 --- a/recursion/program/src/machine/compress.rs +++ b/crates/recursion/program/src/machine/compress.rs @@ -1,6 +1,8 @@ -use std::array; -use std::borrow::{Borrow, BorrowMut}; -use std::marker::PhantomData; +use std::{ + array, + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; use crate::machine::utils::assert_complete; use itertools::{izip, Itertools}; @@ -9,29 +11,36 @@ use p3_baby_bear::BabyBear; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::{AbstractField, PrimeField32, TwoAdicField}; use serde::{Deserialize, Serialize}; -use sp1_core::air::{MachineAir, WORD_SIZE}; -use sp1_core::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}; -use sp1_core::stark::StarkMachine; -use sp1_core::stark::{Com, ShardProof, StarkGenericConfig, StarkVerifyingKey}; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_primitives::types::RecursionProgramType; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::ir::{Array, Builder, Config, Felt, Var}; -use sp1_recursion_compiler::prelude::DslVariable; -use sp1_recursion_core::air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; -use sp1_recursion_core::runtime::{RecursionProgram, D, DIGEST_SIZE}; +use sp1_primitives::{consts::WORD_SIZE, types::RecursionProgramType}; +use sp1_recursion_compiler::{ + config::InnerConfig, + ir::{Array, Builder, Config, Felt, Var}, + prelude::DslVariable, +}; +use sp1_recursion_core::{ + air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}, + runtime::{RecursionProgram, D, DIGEST_SIZE}, +}; +use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, Com, ShardProof, StarkMachine, StarkVerifyingKey, Word, +}; use sp1_recursion_compiler::prelude::*; +use sp1_stark::{ + air::{MachineAir, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}, + StarkGenericConfig, +}; -use crate::challenger::{CanObserveVariable, DuplexChallengerVariable}; -use crate::fri::TwoAdicFriPcsVariable; -use crate::hints::Hintable; -use crate::stark::{RecursiveVerifierConstraintFolder, StarkVerifier}; -use crate::types::ShardProofVariable; -use crate::types::VerifyingKeyVariable; -use crate::utils::{ - assert_challenger_eq_pv, assign_challenger_from_pv, const_fri_config, felt2var, - get_challenger_public_values, hash_vkey, +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable}, + fri::TwoAdicFriPcsVariable, + hints::Hintable, + stark::{RecursiveVerifierConstraintFolder, StarkVerifier}, + types::{ShardProofVariable, VerifyingKeyVariable}, + utils::{ + assert_challenger_eq_pv, assign_challenger_from_pv, const_fri_config, felt2var, + get_challenger_public_values, hash_vkey, + }, }; use super::utils::{commit_public_values, proof_data_from_vk, verify_public_values_hash}; @@ -88,14 +97,7 @@ where let pcs = TwoAdicFriPcsVariable { config: const_fri_config(&mut builder, machine.config().pcs().fri_config()), }; - SP1CompressVerifier::verify( - &mut builder, - &pcs, - machine, - input, - recursive_vk, - deferred_vk, - ); + SP1CompressVerifier::verify(&mut builder, &pcs, machine, input, recursive_vk, deferred_vk); builder.halt(); @@ -121,11 +123,11 @@ where /// implementation in this function assumes a fixed recursive verifier speicified by /// `recursive_vk`. /// - Deferred proofs: proofs which are recursive proof of a batch of deferred proofs. The - /// implementation in this function assumes a fixed deferred verification program specified - /// by `deferred_vk`. - /// - Compress proofs: these are proofs which refer to a prove of this program. The key for - /// it is part of public values will be propagated accross all levels of recursion and will - /// be checked against itself as in [sp1_prover::Prover] or as in [super::SP1RootVerifier]. + /// implementation in this function assumes a fixed deferred verification program specified by + /// `deferred_vk`. + /// - Compress proofs: these are proofs which refer to a prove of this program. The key for it + /// is part of public values will be propagated accross all levels of recursion and will be + /// checked against itself as in [sp1_prover::Prover] or as in [super::SP1RootVerifier]. pub fn verify( builder: &mut Builder, pcs: &TwoAdicFriPcsVariable, @@ -134,18 +136,13 @@ where recursive_vk: &StarkVerifyingKey, deferred_vk: &StarkVerifyingKey, ) { - let SP1CompressMemoryLayoutVariable { - compress_vk, - shard_proofs, - kinds, - is_complete, - } = input; + let SP1CompressMemoryLayoutVariable { compress_vk, shard_proofs, kinds, is_complete } = + input; // Initialize the values for the aggregated public output. - let mut reduce_public_values_stream: Vec> = (0..RECURSIVE_PROOF_NUM_PV_ELTS) - .map(|_| builder.uninit()) - .collect(); + let mut reduce_public_values_stream: Vec> = + (0..RECURSIVE_PROOF_NUM_PV_ELTS).map(|_| builder.uninit()).collect(); let reduce_public_values: &mut RecursionPublicValues<_> = reduce_public_values_stream.as_mut_slice().borrow_mut(); @@ -272,38 +269,27 @@ where // Initialize the start of deferred digests. for (digest, current_digest, global_digest) in izip!( reconstruct_deferred_digest.iter(), - current_public_values - .start_reconstruct_deferred_digest - .iter(), - reduce_public_values - .start_reconstruct_deferred_digest - .iter() + current_public_values.start_reconstruct_deferred_digest.iter(), + reduce_public_values.start_reconstruct_deferred_digest.iter() ) { builder.assign(*digest, *current_digest); builder.assign(*global_digest, *current_digest); } // Initialize the sp1_vk digest - for (digest, first_digest) in sp1_vk_digest - .iter() - .zip(current_public_values.sp1_vk_digest) + for (digest, first_digest) in + sp1_vk_digest.iter().zip(current_public_values.sp1_vk_digest) { builder.assign(*digest, first_digest); } // Initiallize start pc. - builder.assign( - reduce_public_values.start_pc, - current_public_values.start_pc, - ); + builder.assign(reduce_public_values.start_pc, current_public_values.start_pc); builder.assign(pc, current_public_values.start_pc); // Initialize start shard. builder.assign(shard, current_public_values.start_shard); - builder.assign( - reduce_public_values.start_shard, - current_public_values.start_shard, - ); + builder.assign(reduce_public_values.start_shard, current_public_values.start_shard); // Initialize start execution shard. builder.assign(execution_shard, current_public_values.start_execution_shard); @@ -374,21 +360,17 @@ where // Assert that the current values match the accumulated values. // Assert that the start deferred digest is equal to the current deferred digest. - for (digest, current_digest) in reconstruct_deferred_digest.iter().zip_eq( - current_public_values - .start_reconstruct_deferred_digest - .iter(), - ) { + for (digest, current_digest) in reconstruct_deferred_digest + .iter() + .zip_eq(current_public_values.start_reconstruct_deferred_digest.iter()) + { builder.assert_felt_eq(*digest, *current_digest); } // Consistency checks for all accumulated values. // Assert that the sp1_vk digest is always the same. - for (digest, current) in sp1_vk_digest - .iter() - .zip(current_public_values.sp1_vk_digest) - { + for (digest, current) in sp1_vk_digest.iter().zip(current_public_values.sp1_vk_digest) { builder.assert_felt_eq(*digest, current); } @@ -404,9 +386,8 @@ where // Assert that the leaf challenger is always the same. // Assert that the MemoryInitialize address bits are the same. - for (bit, current_bit) in init_addr_bits - .iter() - .zip(current_public_values.previous_init_addr_bits.iter()) + for (bit, current_bit) in + init_addr_bits.iter().zip(current_public_values.previous_init_addr_bits.iter()) { builder.assert_felt_eq(*bit, *current_bit); } @@ -468,8 +449,9 @@ where } } - // If `deferred_proofs_digest` is not zero, then `public_values.deferred_proofs_digest - // should be the current value. + // If `deferred_proofs_digest` is not zero, then + // `public_values.deferred_proofs_digest should be the current + // value. let is_zero: Var<_> = builder.eval(C::N::one()); #[allow(clippy::needless_range_loop)] for i in 0..deferred_proofs_digest.len() { @@ -517,17 +499,15 @@ where builder.assign(execution_shard, current_public_values.next_execution_shard); // Update the MemoryInitialize address bits. - for (bit, next_bit) in init_addr_bits - .iter() - .zip(current_public_values.last_init_addr_bits.iter()) + for (bit, next_bit) in + init_addr_bits.iter().zip(current_public_values.last_init_addr_bits.iter()) { builder.assign(*bit, *next_bit); } // Update the MemoryFinalize address bits. - for (bit, next_bit) in finalize_addr_bits - .iter() - .zip(current_public_values.last_finalize_addr_bits.iter()) + for (bit, next_bit) in + finalize_addr_bits.iter().zip(current_public_values.last_finalize_addr_bits.iter()) { builder.assign(*bit, *next_bit); } @@ -540,9 +520,8 @@ where ); // Update the cumulative sum. - for (sum_element, current_sum_element) in cumulative_sum - .iter() - .zip_eq(current_public_values.cumulative_sum.iter()) + for (sum_element, current_sum_element) in + cumulative_sum.iter().zip_eq(current_public_values.cumulative_sum.iter()) { builder.assign(*sum_element, *sum_element + *current_sum_element); } diff --git a/recursion/program/src/machine/core.rs b/crates/recursion/program/src/machine/core.rs similarity index 84% rename from recursion/program/src/machine/core.rs rename to crates/recursion/program/src/machine/core.rs index 97ea98d13b..560f6dcc0d 100644 --- a/recursion/program/src/machine/core.rs +++ b/crates/recursion/program/src/machine/core.rs @@ -1,32 +1,38 @@ -use std::array; -use std::borrow::{Borrow, BorrowMut}; -use std::marker::PhantomData; +use std::{ + array, + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; use itertools::Itertools; use p3_baby_bear::BabyBear; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::{AbstractField, PrimeField32, TwoAdicField}; -use sp1_core::air::{MachineAir, PublicValues, WORD_SIZE}; -use sp1_core::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}; -use sp1_core::cpu::MAX_CPU_LOG_DEGREE; -use sp1_core::stark::StarkMachine; -use sp1_core::stark::{Com, RiscvAir, ShardProof, StarkGenericConfig, StarkVerifyingKey}; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_primitives::types::RecursionProgramType; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::ir::{Array, Builder, Config, Ext, ExtConst, Felt, Var}; -use sp1_recursion_compiler::prelude::DslVariable; -use sp1_recursion_compiler::prelude::*; -use sp1_recursion_core::air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; -use sp1_recursion_core::runtime::{RecursionProgram, DIGEST_SIZE}; - -use crate::challenger::{CanObserveVariable, DuplexChallengerVariable}; -use crate::fri::TwoAdicFriPcsVariable; -use crate::hints::Hintable; -use crate::stark::{StarkVerifier, EMPTY}; -use crate::types::ShardProofVariable; -use crate::types::VerifyingKeyVariable; -use crate::utils::{const_fri_config, felt2var, get_challenger_public_values, hash_vkey, var2felt}; +use sp1_core_machine::{cpu::MAX_CPU_LOG_DEGREE, riscv::RiscvAir}; +use sp1_primitives::{consts::WORD_SIZE, types::RecursionProgramType}; +use sp1_recursion_compiler::{ + config::InnerConfig, + ir::{Array, Builder, Config, Ext, ExtConst, Felt, Var}, + prelude::{DslVariable, *}, +}; +use sp1_recursion_core::{ + air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}, + runtime::{RecursionProgram, DIGEST_SIZE}, +}; +use sp1_stark::{ + air::{MachineAir, PublicValues, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}, + baby_bear_poseidon2::BabyBearPoseidon2, + Com, ShardProof, StarkGenericConfig, StarkMachine, StarkVerifyingKey, Word, +}; + +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable}, + fri::TwoAdicFriPcsVariable, + hints::Hintable, + stark::{StarkVerifier, EMPTY}, + types::{ShardProofVariable, VerifyingKeyVariable}, + utils::{const_fri_config, felt2var, get_challenger_public_values, hash_vkey, var2felt}, +}; use super::utils::{assert_complete, commit_public_values}; @@ -179,23 +185,17 @@ where for (i, chip) in machine.chips().iter().enumerate() { let index = builder.get(&proof.sorted_idxs, i); if chip.name() == "CPU" { - builder - .if_ne(index, C::N::from_canonical_usize(EMPTY)) - .then(|builder| { - builder.assign(contains_cpu, C::N::one()); - }); + builder.if_ne(index, C::N::from_canonical_usize(EMPTY)).then(|builder| { + builder.assign(contains_cpu, C::N::one()); + }); } else if chip.name() == "MemoryInit" { - builder - .if_ne(index, C::N::from_canonical_usize(EMPTY)) - .then(|builder| { - builder.assign(contains_memory_init, C::N::one()); - }); + builder.if_ne(index, C::N::from_canonical_usize(EMPTY)).then(|builder| { + builder.assign(contains_memory_init, C::N::one()); + }); } else if chip.name() == "MemoryFinalize" { - builder - .if_ne(index, C::N::from_canonical_usize(EMPTY)) - .then(|builder| { - builder.assign(contains_memory_finalize, C::N::one()); - }); + builder.if_ne(index, C::N::from_canonical_usize(EMPTY)).then(|builder| { + builder.assign(contains_memory_finalize, C::N::one()); + }); } } @@ -303,13 +303,11 @@ where let cpu_log_degree = builder.get(&proof.opened_values.chips, index).log_degree; let cpu_log_degree_lt_max: Var<_> = builder.eval(C::N::zero()); - builder - .range(0, MAX_CPU_LOG_DEGREE + 1) - .for_each(|j, builder| { - builder.if_eq(j, cpu_log_degree).then(|builder| { - builder.assign(cpu_log_degree_lt_max, C::N::one()); - }); + builder.range(0, MAX_CPU_LOG_DEGREE + 1).for_each(|j, builder| { + builder.if_eq(j, cpu_log_degree).then(|builder| { + builder.assign(cpu_log_degree_lt_max, C::N::one()); }); + }); builder.assert_var_eq(cpu_log_degree_lt_max, C::N::one()); }); } @@ -333,12 +331,10 @@ where builder.assert_felt_eq(current_execution_shard, public_values.execution_shard); }); - // If the shard has a "CPU" chip, then the execution shard should be incremented by 1. + // If the shard has a "CPU" chip, then the execution shard should be incremented by + // 1. builder.if_eq(contains_cpu, C::N::one()).then(|builder| { - builder.assign( - current_execution_shard, - current_execution_shard + C::F::one(), - ); + builder.assign(current_execution_shard, current_execution_shard + C::F::one()); }); } @@ -375,7 +371,8 @@ where // Memory initialization & finalization constraints. { - // Assert that `init_addr_bits` and `finalize_addr_bits` are zero for the first execution shard. + // Assert that `init_addr_bits` and `finalize_addr_bits` are zero for the first + // execution shard. builder.if_eq(execution_shard, C::N::one()).then(|builder| { // Assert that the MemoryInitialize address bits are zero. for bit in current_init_addr_bits.iter() { @@ -405,35 +402,30 @@ where } // Assert that if MemoryInit is not present, then the address bits are the same. - builder - .if_ne(contains_memory_init, C::N::one()) - .then(|builder| { - for (prev_bit, last_bit) in public_values - .previous_init_addr_bits - .iter() - .zip_eq(public_values.last_init_addr_bits.iter()) - { - builder.assert_felt_eq(*prev_bit, *last_bit); - } - }); + builder.if_ne(contains_memory_init, C::N::one()).then(|builder| { + for (prev_bit, last_bit) in public_values + .previous_init_addr_bits + .iter() + .zip_eq(public_values.last_init_addr_bits.iter()) + { + builder.assert_felt_eq(*prev_bit, *last_bit); + } + }); // Assert that if MemoryFinalize is not present, then the address bits are the same. - builder - .if_ne(contains_memory_finalize, C::N::one()) - .then(|builder| { - for (prev_bit, last_bit) in public_values - .previous_finalize_addr_bits - .iter() - .zip_eq(public_values.last_finalize_addr_bits.iter()) - { - builder.assert_felt_eq(*prev_bit, *last_bit); - } - }); + builder.if_ne(contains_memory_finalize, C::N::one()).then(|builder| { + for (prev_bit, last_bit) in public_values + .previous_finalize_addr_bits + .iter() + .zip_eq(public_values.last_finalize_addr_bits.iter()) + { + builder.assert_felt_eq(*prev_bit, *last_bit); + } + }); // Update the MemoryInitialize address bits. - for (bit, pub_bit) in current_init_addr_bits - .iter() - .zip(public_values.last_init_addr_bits.iter()) + for (bit, pub_bit) in + current_init_addr_bits.iter().zip(public_values.last_init_addr_bits.iter()) { builder.assign(*bit, *pub_bit); } @@ -473,7 +465,8 @@ where } }); - // If it's not a shard with "CPU", then the committed value digest should not change. + // If it's not a shard with "CPU", then the committed value digest should not + // change. builder.if_ne(contains_cpu, C::N::one()).then(|builder| { #[allow(clippy::needless_range_loop)] for i in 0..committed_value_digest.len() { @@ -497,8 +490,9 @@ where } } - // If `deferred_proofs_digest` is not zero, then `public_values.deferred_proofs_digest - // should be the current value. + // If `deferred_proofs_digest` is not zero, then + // `public_values.deferred_proofs_digest should be the current + // value. let is_zero: Var<_> = builder.eval(C::N::one()); #[allow(clippy::needless_range_loop)] for i in 0..deferred_proofs_digest.len() { @@ -517,7 +511,8 @@ where } }); - // If it's not a shard with "CPU", then the deferred proofs digest should not change. + // If it's not a shard with "CPU", then the deferred proofs digest should not + // change. builder.if_ne(contains_cpu, C::N::one()).then(|builder| { #[allow(clippy::needless_range_loop)] for i in 0..deferred_proofs_digest.len() { @@ -531,10 +526,8 @@ where // Update the deferred proofs digest. #[allow(clippy::needless_range_loop)] for i in 0..deferred_proofs_digest.len() { - builder.assign( - deferred_proofs_digest[i], - public_values.deferred_proofs_digest[i], - ); + builder + .assign(deferred_proofs_digest[i], public_values.deferred_proofs_digest[i]); } } @@ -550,13 +543,11 @@ where // Cumulative sum is updated by sums of all chips. let opened_values = proof.opened_values.chips; - builder - .range(0, opened_values.len()) - .for_each(|k, builder| { - let values = builder.get(&opened_values, k); - let sum = values.cumulative_sum; - builder.assign(cumulative_sum, cumulative_sum + sum); - }); + builder.range(0, opened_values.len()).for_each(|k, builder| { + let values = builder.get(&opened_values, k); + let sum = values.cumulative_sum; + builder.assign(cumulative_sum, cumulative_sum + sum); + }); }); // Write all values to the public values struct and commit to them. @@ -612,9 +603,9 @@ where // If the proof represents a complete proof, make completeness assertions. // - // *Remark*: In this program, this only happends if there is one shard and the program has - // no deferred proofs to verify. However, the completeness check is independent of these - // facts. + // *Remark*: In this program, this only happends if there is one shard and the program + // has no deferred proofs to verify. However, the completeness check is + // independent of these facts. builder.if_eq(is_complete, C::N::one()).then(|builder| { assert_complete(builder, recursion_public_values, &reconstruct_challenger) }); diff --git a/recursion/program/src/machine/deferred.rs b/crates/recursion/program/src/machine/deferred.rs similarity index 87% rename from recursion/program/src/machine/deferred.rs rename to crates/recursion/program/src/machine/deferred.rs index 9dfef395c4..ef0b7d4538 100644 --- a/recursion/program/src/machine/deferred.rs +++ b/crates/recursion/program/src/machine/deferred.rs @@ -1,32 +1,40 @@ -use std::array; -use std::borrow::{Borrow, BorrowMut}; -use std::marker::PhantomData; +use std::{ + array, + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; use p3_air::Air; use p3_baby_bear::BabyBear; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::{AbstractField, PrimeField32, TwoAdicField}; -use sp1_core::air::{MachineAir, WORD_SIZE}; -use sp1_core::air::{Word, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}; -use sp1_core::stark::StarkMachine; -use sp1_core::stark::{Com, RiscvAir, ShardProof, StarkGenericConfig, StarkVerifyingKey}; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_primitives::types::RecursionProgramType; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::ir::{Array, Builder, Config, Felt, Var}; -use sp1_recursion_compiler::prelude::DslVariable; -use sp1_recursion_core::air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; -use sp1_recursion_core::runtime::{RecursionProgram, DIGEST_SIZE}; +use sp1_core_machine::riscv::RiscvAir; +use sp1_primitives::{consts::WORD_SIZE, types::RecursionProgramType}; +use sp1_recursion_compiler::{ + config::InnerConfig, + ir::{Array, Builder, Config, Felt, Var}, + prelude::DslVariable, +}; +use sp1_recursion_core::{ + air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}, + runtime::{RecursionProgram, DIGEST_SIZE}, +}; use sp1_recursion_compiler::prelude::*; - -use crate::challenger::{CanObserveVariable, DuplexChallengerVariable}; -use crate::fri::TwoAdicFriPcsVariable; -use crate::hints::Hintable; -use crate::stark::{RecursiveVerifierConstraintFolder, StarkVerifier}; -use crate::types::ShardProofVariable; -use crate::types::VerifyingKeyVariable; -use crate::utils::{const_fri_config, get_challenger_public_values, hash_vkey, var2felt}; +use sp1_stark::{ + air::{MachineAir, POSEIDON_NUM_WORDS, PV_DIGEST_NUM_WORDS}, + baby_bear_poseidon2::BabyBearPoseidon2, + Com, ShardProof, StarkGenericConfig, StarkMachine, StarkVerifyingKey, Word, +}; + +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable}, + fri::TwoAdicFriPcsVariable, + hints::Hintable, + stark::{RecursiveVerifierConstraintFolder, StarkVerifier}, + types::{ShardProofVariable, VerifyingKeyVariable}, + utils::{const_fri_config, get_challenger_public_values, hash_vkey, var2felt}, +}; use super::utils::{commit_public_values, verify_public_values_hash}; @@ -148,9 +156,8 @@ where } = input; // Initialize the values for the aggregated public output as all zeros. - let mut deferred_public_values_stream: Vec> = (0..RECURSIVE_PROOF_NUM_PV_ELTS) - .map(|_| builder.eval(C::F::zero())) - .collect(); + let mut deferred_public_values_stream: Vec> = + (0..RECURSIVE_PROOF_NUM_PV_ELTS).map(|_| builder.eval(C::F::zero())).collect(); let deferred_public_values: &mut RecursionPublicValues<_> = deferred_public_values_stream.as_mut_slice().borrow_mut(); @@ -170,10 +177,8 @@ where // Initialize the consistency check variable. let mut reconstruct_deferred_digest = builder.array(POSEIDON_NUM_WORDS); - for (i, first_digest) in deferred_public_values - .start_reconstruct_deferred_digest - .iter() - .enumerate() + for (i, first_digest) in + deferred_public_values.start_reconstruct_deferred_digest.iter().enumerate() { builder.set(&mut reconstruct_deferred_digest, i, *first_digest); } @@ -232,7 +237,8 @@ where } // Update deferred proof digest - // poseidon2( current_digest[..8] || pv.sp1_vk_digest[..8] || pv.committed_value_digest[..32] ) + // poseidon2( current_digest[..8] || pv.sp1_vk_digest[..8] || + // pv.committed_value_digest[..32] ) let mut poseidon_inputs = builder.array(48); for j in 0..DIGEST_SIZE { let current_digest_element = builder.get(&reconstruct_deferred_digest, j); @@ -284,10 +290,7 @@ where deferred_public_values.sp1_vk_digest = array::from_fn(|i| builder.get(&sp1_vk_digest, i)); // Set the committed value digest to be the hitned value. - for (i, public_word) in deferred_public_values - .committed_value_digest - .iter_mut() - .enumerate() + for (i, public_word) in deferred_public_values.committed_value_digest.iter_mut().enumerate() { let hinted_word = builder.get(&committed_value_digest, i); public_word.0 = array::from_fn(|j| builder.get(&hinted_word, j)); diff --git a/recursion/program/src/machine/mod.rs b/crates/recursion/program/src/machine/mod.rs similarity index 100% rename from recursion/program/src/machine/mod.rs rename to crates/recursion/program/src/machine/mod.rs diff --git a/recursion/program/src/machine/root.rs b/crates/recursion/program/src/machine/root.rs similarity index 83% rename from recursion/program/src/machine/root.rs rename to crates/recursion/program/src/machine/root.rs index 6662c2b8e2..2b19c1735c 100644 --- a/recursion/program/src/machine/root.rs +++ b/crates/recursion/program/src/machine/root.rs @@ -4,26 +4,32 @@ use p3_air::Air; use p3_baby_bear::BabyBear; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::{AbstractField, PrimeField32, TwoAdicField}; -use sp1_core::air::MachineAir; -use sp1_core::stark::StarkMachine; -use sp1_core::stark::{Com, ShardProof, StarkGenericConfig, StarkVerifyingKey}; -use sp1_core::utils::BabyBearPoseidon2; use sp1_primitives::types::RecursionProgramType; -use sp1_recursion_compiler::config::InnerConfig; -use sp1_recursion_compiler::ir::{Builder, Config, Felt, Var}; -use sp1_recursion_compiler::prelude::DslVariable; -use sp1_recursion_core::air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}; -use sp1_recursion_core::runtime::{RecursionProgram, DIGEST_SIZE}; +use sp1_recursion_compiler::{ + config::InnerConfig, + ir::{Builder, Config, Felt, Var}, + prelude::DslVariable, +}; +use sp1_recursion_core::{ + air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS}, + runtime::{RecursionProgram, DIGEST_SIZE}, +}; use sp1_recursion_compiler::prelude::*; - -use crate::challenger::{CanObserveVariable, DuplexChallengerVariable}; -use crate::fri::TwoAdicFriPcsVariable; -use crate::hints::Hintable; -use crate::machine::utils::proof_data_from_vk; -use crate::stark::{RecursiveVerifierConstraintFolder, ShardProofHint, StarkVerifier}; -use crate::types::ShardProofVariable; -use crate::utils::{const_fri_config, hash_vkey}; +use sp1_stark::{ + air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, Com, ShardProof, StarkGenericConfig, + StarkMachine, StarkVerifyingKey, +}; + +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable}, + fri::TwoAdicFriPcsVariable, + hints::Hintable, + machine::utils::proof_data_from_vk, + stark::{RecursiveVerifierConstraintFolder, ShardProofHint, StarkVerifier}, + types::ShardProofVariable, + utils::{const_fri_config, hash_vkey}, +}; use super::utils::{commit_public_values, verify_public_values_hash}; @@ -55,10 +61,7 @@ where vk: &StarkVerifyingKey, program_type: RecursionProgramType, ) -> RecursionProgram { - assert!(matches!( - program_type, - RecursionProgramType::Shrink | RecursionProgramType::Wrap - )); + assert!(matches!(program_type, RecursionProgramType::Shrink | RecursionProgramType::Wrap)); let mut builder = Builder::::new(program_type); diff --git a/recursion/program/src/machine/utils.rs b/crates/recursion/program/src/machine/utils.rs similarity index 93% rename from recursion/program/src/machine/utils.rs rename to crates/recursion/program/src/machine/utils.rs index 424d1a229d..15ea3100c4 100644 --- a/recursion/program/src/machine/utils.rs +++ b/crates/recursion/program/src/machine/utils.rs @@ -4,15 +4,12 @@ use itertools::Itertools; use p3_commit::TwoAdicMultiplicativeCoset; use p3_field::AbstractField; -use sp1_core::{ - air::MachineAir, - stark::{Com, StarkGenericConfig, StarkMachine, StarkVerifyingKey}, -}; use sp1_recursion_compiler::ir::{Array, Builder, Config, Felt, Var}; use sp1_recursion_core::{ air::{RecursionPublicValues, NUM_PV_ELMS_TO_HASH, RECURSIVE_PROOF_NUM_PV_ELTS}, runtime::DIGEST_SIZE, }; +use sp1_stark::{air::MachineAir, Com, StarkGenericConfig, StarkMachine, StarkVerifyingKey}; use crate::{ challenger::DuplexChallengerVariable, @@ -49,7 +46,8 @@ pub(crate) fn assert_complete( // Assert that start shard is equal to 1. builder.assert_felt_eq(*start_shard, C::F::one()); - // Assert that the next shard is not equal to one. This guarantees that there is at least one shard. + // Assert that the next shard is not equal to one. This guarantees that there is at least one + // shard. builder.assert_felt_ne(*next_shard, C::F::one()); // Assert that the start execution shard is equal to 1. @@ -68,9 +66,8 @@ pub(crate) fn assert_complete( } // The end reconstruct deffered digest should be equal to the deferred proofs digest. - for (end_digest_word, deferred_digest_word) in end_reconstruct_deferred_digest - .iter() - .zip_eq(deferred_proofs_digest.iter()) + for (end_digest_word, deferred_digest_word) in + end_reconstruct_deferred_digest.iter().zip_eq(deferred_proofs_digest.iter()) { builder.assert_felt_eq(*end_digest_word, *deferred_digest_word); } @@ -108,11 +105,7 @@ where builder.dyn_array::>(prep_domains_val.len()); for (i, value) in prep_sorted_indices_val.iter().enumerate() { - builder.set( - &mut prep_sorted_indices, - i, - C::N::from_canonical_usize(*value), - ); + builder.set(&mut prep_sorted_indices, i, C::N::from_canonical_usize(*value)); } for (i, value) in prep_domains_val.iter().enumerate() { diff --git a/recursion/program/src/stark.rs b/crates/recursion/program/src/stark.rs similarity index 69% rename from recursion/program/src/stark.rs rename to crates/recursion/program/src/stark.rs index dc16a2668d..607b6e52df 100644 --- a/recursion/program/src/stark.rs +++ b/crates/recursion/program/src/stark.rs @@ -1,36 +1,27 @@ use p3_air::Air; use p3_commit::TwoAdicMultiplicativeCoset; -use p3_field::AbstractField; -use p3_field::TwoAdicField; -use sp1_core::air::MachineAir; -use sp1_core::stark::Com; -use sp1_core::stark::GenericVerifierConstraintFolder; -use sp1_core::stark::ShardProof; -use sp1_core::stark::StarkGenericConfig; -use sp1_core::stark::StarkMachine; - -use sp1_core::stark::StarkVerifyingKey; -use sp1_recursion_compiler::ir::Array; -use sp1_recursion_compiler::ir::Ext; -use sp1_recursion_compiler::ir::ExtConst; -use sp1_recursion_compiler::ir::SymbolicExt; -use sp1_recursion_compiler::ir::SymbolicVar; -use sp1_recursion_compiler::ir::Var; -use sp1_recursion_compiler::ir::{Builder, Config, Usize}; -use sp1_recursion_compiler::prelude::Felt; +use p3_field::{AbstractField, TwoAdicField}; -use sp1_recursion_core::runtime::DIGEST_SIZE; +use sp1_recursion_compiler::{ + ir::{Array, Builder, Config, Ext, ExtConst, SymbolicExt, SymbolicVar, Usize, Var}, + prelude::Felt, +}; -use crate::challenger::CanObserveVariable; -use crate::challenger::DuplexChallengerVariable; -use crate::challenger::FeltChallenger; -use crate::commit::PolynomialSpaceVariable; -use crate::fri::types::TwoAdicPcsMatsVariable; -use crate::fri::types::TwoAdicPcsRoundVariable; -use crate::fri::TwoAdicMultiplicativeCosetVariable; -use crate::types::ShardCommitmentVariable; -use crate::types::VerifyingKeyVariable; -use crate::{commit::PcsVariable, fri::TwoAdicFriPcsVariable, types::ShardProofVariable}; +use sp1_recursion_core::runtime::DIGEST_SIZE; +use sp1_stark::{ + air::MachineAir, Com, GenericVerifierConstraintFolder, ShardProof, StarkGenericConfig, + StarkMachine, StarkVerifyingKey, +}; + +use crate::{ + challenger::{CanObserveVariable, DuplexChallengerVariable, FeltChallenger}, + commit::{PcsVariable, PolynomialSpaceVariable}, + fri::{ + types::{TwoAdicPcsMatsVariable, TwoAdicPcsRoundVariable}, + TwoAdicFriPcsVariable, TwoAdicMultiplicativeCosetVariable, + }, + types::{ShardCommitmentVariable, ShardProofVariable, VerifyingKeyVariable}, +}; use crate::types::QuotientData; @@ -127,22 +118,13 @@ where Com: Into<[SC::Val; DIGEST_SIZE]>, { builder.cycle_tracker("stage-c-verify-shard-setup"); - let ShardProofVariable { - commitment, - opened_values, - opening_proof, - .. - } = proof; - - let ShardCommitmentVariable { - main_commit, - permutation_commit, - quotient_commit, - } = commitment; - - let permutation_challenges = (0..2) - .map(|_| challenger.sample_ext(builder)) - .collect::>(); + let ShardProofVariable { commitment, opened_values, opening_proof, .. } = proof; + + let ShardCommitmentVariable { main_commit, permutation_commit, quotient_commit } = + commitment; + + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext(builder)).collect::>(); challenger.observe(builder, permutation_commit.clone()); @@ -209,10 +191,8 @@ where let qc_index: Var<_> = builder.eval(C::N::zero()); builder.range(0, num_shard_chips).for_each(|i, builder| { let opening = builder.get(&opened_values.chips, i); - let QuotientData { - log_quotient_degree, - quotient_size, - } = builder.get(&proof.quotient_data, i); + let QuotientData { log_quotient_degree, quotient_size } = + builder.get(&proof.quotient_data, i); let domain = pcs.natural_domain_for_log_degree(builder, Usize::Var(opening.log_degree)); builder.set_value(&mut trace_domains, i, domain.clone()); @@ -272,22 +252,13 @@ where // Create the pcs rounds. let mut rounds = builder.dyn_array::>(4); let prep_commit = vk.commitment.clone(); - let prep_round = TwoAdicPcsRoundVariable { - batch_commit: prep_commit, - mats: prep_mats, - }; - let main_round = TwoAdicPcsRoundVariable { - batch_commit: main_commit.clone(), - mats: main_mats, - }; - let perm_round = TwoAdicPcsRoundVariable { - batch_commit: permutation_commit.clone(), - mats: perm_mats, - }; - let quotient_round = TwoAdicPcsRoundVariable { - batch_commit: quotient_commit.clone(), - mats: quotient_mats, - }; + let prep_round = TwoAdicPcsRoundVariable { batch_commit: prep_commit, mats: prep_mats }; + let main_round = + TwoAdicPcsRoundVariable { batch_commit: main_commit.clone(), mats: main_mats }; + let perm_round = + TwoAdicPcsRoundVariable { batch_commit: permutation_commit.clone(), mats: perm_mats }; + let quotient_round = + TwoAdicPcsRoundVariable { batch_commit: quotient_commit.clone(), mats: quotient_mats }; builder.set_value(&mut rounds, 0, prep_round); builder.set_value(&mut rounds, 1, main_round); builder.set_value(&mut rounds, 2, perm_round); @@ -310,64 +281,55 @@ where builder.assert_var_ne(index, C::N::from_canonical_usize(EMPTY)); } - builder - .if_ne(index, C::N::from_canonical_usize(EMPTY)) - .then(|builder| { - let values = builder.get(&opened_values.chips, index); - let trace_domain = builder.get(&trace_domains, index); - let quotient_domain: TwoAdicMultiplicativeCosetVariable<_> = - builder.get("ient_domains, index); - - // Check that the quotient data matches the chip's data. - let log_quotient_degree = chip.log_quotient_degree(); - - let quotient_size = 1 << log_quotient_degree; - let chip_quotient_data = builder.get(&proof.quotient_data, index); - builder.assert_usize_eq( - chip_quotient_data.log_quotient_degree, - log_quotient_degree, - ); - builder.assert_usize_eq(chip_quotient_data.quotient_size, quotient_size); - - // Get the domains from the chip itself. - let qc_domains = - quotient_domain.split_domains_const(builder, log_quotient_degree); - - // Verify the constraints. - stacker::maybe_grow(16 * 1024 * 1024, 16 * 1024 * 1024, || { - Self::verify_constraints( - builder, - chip, - &values, - proof.public_values.clone(), - trace_domain, - qc_domains, - zeta, - alpha, - &permutation_challenges, - ); - }); - - // Increment the number of shard chips that are enabled. - builder.assign( - num_shard_chips_enabled, - num_shard_chips_enabled + C::N::one(), + builder.if_ne(index, C::N::from_canonical_usize(EMPTY)).then(|builder| { + let values = builder.get(&opened_values.chips, index); + let trace_domain = builder.get(&trace_domains, index); + let quotient_domain: TwoAdicMultiplicativeCosetVariable<_> = + builder.get("ient_domains, index); + + // Check that the quotient data matches the chip's data. + let log_quotient_degree = chip.log_quotient_degree(); + + let quotient_size = 1 << log_quotient_degree; + let chip_quotient_data = builder.get(&proof.quotient_data, index); + builder + .assert_usize_eq(chip_quotient_data.log_quotient_degree, log_quotient_degree); + builder.assert_usize_eq(chip_quotient_data.quotient_size, quotient_size); + + // Get the domains from the chip itself. + let qc_domains = quotient_domain.split_domains_const(builder, log_quotient_degree); + + // Verify the constraints. + stacker::maybe_grow(16 * 1024 * 1024, 16 * 1024 * 1024, || { + Self::verify_constraints( + builder, + chip, + &values, + proof.public_values.clone(), + trace_domain, + qc_domains, + zeta, + alpha, + &permutation_challenges, ); }); + + // Increment the number of shard chips that are enabled. + builder.assign(num_shard_chips_enabled, num_shard_chips_enabled + C::N::one()); + }); } - // Assert that the number of chips in `opened_values` matches the number of shard chips enabled. + // Assert that the number of chips in `opened_values` matches the number of shard chips + // enabled. builder.assert_var_eq(num_shard_chips_enabled, num_shard_chips); // If we're checking the cumulative sum, assert that the sum of the cumulative sums is zero. if check_cumulative_sum { let sum: Ext<_, _> = builder.eval(C::EF::zero().cons()); - builder - .range(0, proof.opened_values.chips.len()) - .for_each(|i, builder| { - let cumulative_sum = builder.get(&proof.opened_values.chips, i).cumulative_sum; - builder.assign(sum, sum + cumulative_sum); - }); + builder.range(0, proof.opened_values.chips.len()).for_each(|i, builder| { + let cumulative_sum = builder.get(&proof.opened_values.chips, i).cumulative_sum; + builder.assign(sum, sum + cumulative_sum); + }); builder.assert_ext_eq(sum, C::EF::zero().cons()); } @@ -377,53 +339,39 @@ where #[cfg(test)] pub(crate) mod tests { - use std::borrow::BorrowMut; - use std::time::Instant; - - use crate::challenger::CanObserveVariable; - use crate::challenger::FeltChallenger; - use crate::hints::Hintable; - use crate::machine::commit_public_values; - use crate::stark::DuplexChallengerVariable; - use crate::stark::Ext; - use crate::stark::ShardProofHint; - use crate::types::ShardCommitmentVariable; + use std::{borrow::BorrowMut, time::Instant}; + + use crate::{ + challenger::{CanObserveVariable, FeltChallenger}, + hints::Hintable, + machine::commit_public_values, + stark::{DuplexChallengerVariable, Ext, ShardProofHint}, + types::ShardCommitmentVariable, + }; use p3_challenger::{CanObserve, FieldChallenger}; use p3_field::AbstractField; use rand::Rng; - use sp1_core::air::POSEIDON_NUM_WORDS; - use sp1_core::io::SP1Stdin; - use sp1_core::runtime::Program; - use sp1_core::stark::CpuProver; - use sp1_core::stark::MachineProver; - use sp1_core::utils::setup_logger; - use sp1_core::utils::InnerChallenge; - use sp1_core::utils::InnerVal; - use sp1_core::utils::SP1CoreOpts; - use sp1_core::{ - stark::{RiscvAir, StarkGenericConfig}, - utils::BabyBearPoseidon2, - }; - use sp1_recursion_compiler::config::InnerConfig; - use sp1_recursion_compiler::ir::Array; - use sp1_recursion_compiler::ir::Config; - use sp1_recursion_compiler::ir::Felt; - use sp1_recursion_compiler::prelude::Usize; + use sp1_core_executor::Program; + use sp1_core_machine::{io::SP1Stdin, riscv::RiscvAir, utils::setup_logger}; use sp1_recursion_compiler::{ asm::AsmBuilder, - ir::{Builder, ExtConst}, + config::InnerConfig, + ir::{Array, Builder, Config, ExtConst, Felt, Usize}, + }; + use sp1_recursion_core::{ + air::{ + RecursionPublicValues, RECURSION_PUBLIC_VALUES_COL_MAP, RECURSIVE_PROOF_NUM_PV_ELTS, + }, + runtime::{RecursionProgram, Runtime, DIGEST_SIZE}, + stark::{ + utils::{run_test_recursion, TestConfig}, + RecursionAir, + }, + }; + use sp1_stark::{ + air::POSEIDON_NUM_WORDS, baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, InnerChallenge, + InnerVal, MachineProver, SP1CoreOpts, StarkGenericConfig, }; - - use sp1_recursion_core::air::RecursionPublicValues; - use sp1_recursion_core::air::RECURSION_PUBLIC_VALUES_COL_MAP; - use sp1_recursion_core::air::RECURSIVE_PROOF_NUM_PV_ELTS; - use sp1_recursion_core::runtime::RecursionProgram; - use sp1_recursion_core::runtime::Runtime; - use sp1_recursion_core::runtime::DIGEST_SIZE; - - use sp1_recursion_core::stark::utils::run_test_recursion; - use sp1_recursion_core::stark::utils::TestConfig; - use sp1_recursion_core::stark::RecursionAir; type SC = BabyBearPoseidon2; type Challenge = ::Challenge; @@ -435,14 +383,14 @@ pub(crate) mod tests { #[test] fn test_permutation_challenges() { // Generate a dummy proof. - sp1_core::utils::setup_logger(); - let elf = include_bytes!("../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); + sp1_core_machine::utils::setup_logger(); + let elf = include_bytes!("../../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf"); let machine = A::machine(SC::default()); - let (_, vk) = machine.setup(&Program::from(elf)); + let (_, vk) = machine.setup(&Program::from(elf).unwrap()); let mut challenger_val = machine.config().challenger(); - let (proof, _, _) = sp1_core::utils::prove::<_, CpuProver<_, _>>( - Program::from(elf), + let (proof, _, _) = sp1_core_machine::utils::prove::<_, CpuProver<_, _>>( + Program::from(elf).unwrap(), &SP1Stdin::new(), SC::default(), SP1CoreOpts::default(), @@ -458,9 +406,8 @@ pub(crate) mod tests { challenger_val.observe_slice(&proof.public_values[0..machine.num_pv_elts()]); }); - let permutation_challenges = (0..2) - .map(|_| challenger_val.sample_ext_element::()) - .collect::>(); + let permutation_challenges = + (0..2).map(|_| challenger_val.sample_ext_element::()).collect::>(); // Observe all the commitments. let mut builder = Builder::::default(); @@ -491,15 +438,11 @@ pub(crate) mod tests { } // Sample the permutation challenges. - let permutation_challenges_var = (0..2) - .map(|_| challenger.sample_ext(&mut builder)) - .collect::>(); + let permutation_challenges_var = + (0..2).map(|_| challenger.sample_ext(&mut builder)).collect::>(); for i in 0..2 { - builder.assert_ext_eq( - permutation_challenges_var[i], - permutation_challenges[i].cons(), - ); + builder.assert_ext_eq(permutation_challenges_var[i], permutation_challenges[i].cons()); } builder.halt(); @@ -514,9 +457,8 @@ pub(crate) mod tests { let hash_input = builder.constant(vec![vec![F::one()]]); builder.poseidon2_hash_x(&hash_input); - let mut public_values_stream: Vec> = (0..RECURSIVE_PROOF_NUM_PV_ELTS) - .map(|_| builder.uninit()) - .collect(); + let mut public_values_stream: Vec> = + (0..RECURSIVE_PROOF_NUM_PV_ELTS).map(|_| builder.uninit()).collect(); let public_values: &mut RecursionPublicValues<_> = public_values_stream.as_mut_slice().borrow_mut(); @@ -554,9 +496,8 @@ pub(crate) mod tests { let record = runtime.record.clone(); let mut challenger = prover.config().challenger(); - let mut proof = prover - .prove(&pk, vec![record], &mut challenger, SP1CoreOpts::recursion()) - .unwrap(); + let mut proof = + prover.prove(&pk, vec![record], &mut challenger, SP1CoreOpts::recursion()).unwrap(); let mut challenger = prover.config().challenger(); let verification_result = prover.machine().verify(&vk, &proof, &mut challenger); diff --git a/recursion/program/src/types.rs b/crates/recursion/program/src/types.rs similarity index 83% rename from recursion/program/src/types.rs rename to crates/recursion/program/src/types.rs index db49b10eb5..ab3881e76b 100644 --- a/recursion/program/src/types.rs +++ b/crates/recursion/program/src/types.rs @@ -1,16 +1,18 @@ use p3_air::BaseAir; use p3_field::{AbstractExtensionField, AbstractField}; -use sp1_core::{ - air::{MachineAir, Word, PV_DIGEST_NUM_WORDS, WORD_SIZE}, - stark::{AirOpenedValues, Chip, ChipOpenedValues}, -}; +use sp1_primitives::consts::WORD_SIZE; use sp1_recursion_compiler::prelude::*; +use sp1_stark::{ + air::{MachineAir, PV_DIGEST_NUM_WORDS}, + AirOpenedValues, Chip, ChipOpenedValues, Word, +}; -use crate::fri::types::TwoAdicPcsProofVariable; -use crate::fri::types::{DigestVariable, FriConfigVariable}; -use crate::fri::TwoAdicMultiplicativeCosetVariable; +use crate::fri::{ + types::{DigestVariable, FriConfigVariable, TwoAdicPcsProofVariable}, + TwoAdicMultiplicativeCosetVariable, +}; -/// Reference: [sp1_core::stark::ShardProof] +/// Reference: [sp1_core_machine::stark::ShardProof] #[derive(DslVariable, Clone)] pub struct ShardProofVariable { pub commitment: ShardCommitmentVariable, @@ -33,7 +35,7 @@ pub struct QuotientDataValues { pub quotient_size: usize, } -/// Reference: [sp1_core::stark::VerifyingKey] +/// Reference: [sp1_core_machine::stark::VerifyingKey] #[derive(DslVariable, Clone)] pub struct VerifyingKeyVariable { pub commitment: DigestVariable, @@ -42,7 +44,7 @@ pub struct VerifyingKeyVariable { pub prep_domains: Array>, } -/// Reference: [sp1_core::stark::ShardCommitment] +/// Reference: [sp1_core_machine::stark::ShardCommitment] #[derive(DslVariable, Clone)] pub struct ShardCommitmentVariable { pub main_commit: DigestVariable, @@ -50,13 +52,13 @@ pub struct ShardCommitmentVariable { pub quotient_commit: DigestVariable, } -/// Reference: [sp1_core::stark::ShardOpenedValues] +/// Reference: [sp1_core_machine::stark::ShardOpenedValues] #[derive(DslVariable, Debug, Clone)] pub struct ShardOpenedValuesVariable { pub chips: Array>, } -/// Reference: [sp1_core::stark::ChipOpenedValues] +/// Reference: [sp1_core_machine::stark::ChipOpenedValues] #[derive(Debug, Clone)] pub struct ChipOpening { pub preprocessed: AirOpenedValues>, @@ -67,7 +69,7 @@ pub struct ChipOpening { pub log_degree: Var, } -/// Reference: [sp1_core::stark::ChipOpenedValues] +/// Reference: [sp1_core_machine::stark::ChipOpenedValues] #[derive(DslVariable, Debug, Clone)] pub struct ChipOpenedValuesVariable { pub preprocessed: AirOpenedValuesVariable, @@ -78,7 +80,7 @@ pub struct ChipOpenedValuesVariable { pub log_degree: Var, } -/// Reference: [sp1_core::stark::AirOpenedValues] +/// Reference: [sp1_core_machine::stark::AirOpenedValues] #[derive(DslVariable, Debug, Clone)] pub struct AirOpenedValuesVariable { pub local: Array>, @@ -119,28 +121,18 @@ impl ChipOpening { where A: MachineAir, { - let mut preprocessed = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut preprocessed = AirOpenedValues { local: vec![], next: vec![] }; let preprocessed_width = chip.preprocessed_width(); // Assert that the length of the dynamic arrays match the expected length of the vectors. builder.assert_usize_eq(preprocessed_width, opening.preprocessed.local.len()); builder.assert_usize_eq(preprocessed_width, opening.preprocessed.next.len()); // Collect the preprocessed values into vectors. for i in 0..preprocessed_width { - preprocessed - .local - .push(builder.get(&opening.preprocessed.local, i)); - preprocessed - .next - .push(builder.get(&opening.preprocessed.next, i)); + preprocessed.local.push(builder.get(&opening.preprocessed.local, i)); + preprocessed.next.push(builder.get(&opening.preprocessed.next, i)); } - let mut main = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut main = AirOpenedValues { local: vec![], next: vec![] }; let main_width = chip.width(); // Assert that the length of the dynamic arrays match the expected length of the vectors. builder.assert_usize_eq(main_width, opening.main.local.len()); @@ -151,22 +143,15 @@ impl ChipOpening { main.next.push(builder.get(&opening.main.next, i)); } - let mut permutation = AirOpenedValues { - local: vec![], - next: vec![], - }; + let mut permutation = AirOpenedValues { local: vec![], next: vec![] }; let permutation_width = C::EF::D * chip.permutation_width(); // Assert that the length of the dynamic arrays match the expected length of the vectors. builder.assert_usize_eq(permutation_width, opening.permutation.local.len()); builder.assert_usize_eq(permutation_width, opening.permutation.next.len()); // Collect the permutation values into vectors. for i in 0..permutation_width { - permutation - .local - .push(builder.get(&opening.permutation.local, i)); - permutation - .next - .push(builder.get(&opening.permutation.next, i)); + permutation.local.push(builder.get(&opening.permutation.local, i)); + permutation.next.push(builder.get(&opening.permutation.next, i)); } let num_quotient_chunks = 1 << chip.log_quotient_degree(); diff --git a/recursion/program/src/utils.rs b/crates/recursion/program/src/utils.rs similarity index 79% rename from recursion/program/src/utils.rs rename to crates/recursion/program/src/utils.rs index 9122957b14..551a346178 100644 --- a/recursion/program/src/utils.rs +++ b/crates/recursion/program/src/utils.rs @@ -1,24 +1,29 @@ use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; use p3_commit::{ExtensionMmcs, TwoAdicMultiplicativeCoset}; -use p3_field::extension::BinomialExtensionField; -use p3_field::{AbstractField, Field, TwoAdicField}; +use p3_field::{extension::BinomialExtensionField, AbstractField, Field, TwoAdicField}; use p3_fri::FriConfig; use p3_merkle_tree::FieldMerkleTreeMmcs; use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; -use sp1_core::air::MachineAir; -use sp1_core::stark::{Dom, ShardProof, StarkGenericConfig, StarkMachine, StarkVerifyingKey}; -use sp1_core::utils::BabyBearPoseidon2; -use sp1_recursion_compiler::asm::AsmConfig; -use sp1_recursion_compiler::ir::{Array, Builder, Config, Felt, MemVariable, Var}; -use sp1_recursion_core::air::ChallengerPublicValues; -use sp1_recursion_core::runtime::{DIGEST_SIZE, PERMUTATION_WIDTH}; - -use crate::challenger::DuplexChallengerVariable; -use crate::fri::types::FriConfigVariable; -use crate::fri::TwoAdicMultiplicativeCosetVariable; -use crate::stark::EMPTY; -use crate::types::{QuotientDataValues, VerifyingKeyVariable}; +use sp1_recursion_compiler::{ + asm::AsmConfig, + ir::{Array, Builder, Config, Felt, MemVariable, Var}, +}; +use sp1_recursion_core::{ + air::ChallengerPublicValues, + runtime::{DIGEST_SIZE, PERMUTATION_WIDTH}, +}; +use sp1_stark::{ + air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, Dom, ShardProof, StarkGenericConfig, + StarkMachine, StarkVerifyingKey, +}; + +use crate::{ + challenger::DuplexChallengerVariable, + fri::{types::FriConfigVariable, TwoAdicMultiplicativeCosetVariable}, + stark::EMPTY, + types::{QuotientDataValues, VerifyingKeyVariable}, +}; type SC = BabyBearPoseidon2; type F = ::Val; @@ -46,10 +51,7 @@ pub fn const_fri_config( let constant_generator = Val::two_adic_generator(i); builder.set(&mut generators, i, constant_generator); - let constant_domain = TwoAdicMultiplicativeCoset { - log_n: i, - shift: Val::one(), - }; + let constant_domain = TwoAdicMultiplicativeCoset { log_n: i, shift: Val::one() }; let domain_value: TwoAdicMultiplicativeCosetVariable<_> = builder.constant(constant_domain); builder.set(&mut subgroups, i, domain_value); } @@ -157,13 +159,7 @@ pub fn get_challenger_public_values( let num_outputs = var2felt(builder, var.nb_outputs); let output_buffer = core::array::from_fn(|i| builder.get(&var.output_buffer, i)); - ChallengerPublicValues { - sponge_state, - num_inputs, - input_buffer, - num_outputs, - output_buffer, - } + ChallengerPublicValues { sponge_state, num_inputs, input_buffer, num_outputs, output_buffer } } /// Hash the verifying key + prep domains into a single digest. @@ -183,22 +179,20 @@ pub fn hash_vkey( builder.set(&mut inputs, DIGEST_SIZE, vk.pc_start); let four: Var<_> = builder.constant(C::N::from_canonical_usize(4)); let one: Var<_> = builder.constant(C::N::one()); - builder - .range(0, vk.prep_domains.len()) - .for_each(|i, builder| { - let sorted_index = builder.get(&vk.preprocessed_sorted_idxs, i); - let domain = builder.get(&vk.prep_domains, i); - let log_n_index: Var<_> = builder.eval(vkey_slots + sorted_index * four); - let size_index: Var<_> = builder.eval(log_n_index + one); - let shift_index: Var<_> = builder.eval(size_index + one); - let g_index: Var<_> = builder.eval(shift_index + one); - let log_n_felt = var2felt(builder, domain.log_n); - let size_felt = var2felt(builder, domain.size); - builder.set(&mut inputs, log_n_index, log_n_felt); - builder.set(&mut inputs, size_index, size_felt); - builder.set(&mut inputs, shift_index, domain.shift); - builder.set(&mut inputs, g_index, domain.g); - }); + builder.range(0, vk.prep_domains.len()).for_each(|i, builder| { + let sorted_index = builder.get(&vk.preprocessed_sorted_idxs, i); + let domain = builder.get(&vk.prep_domains, i); + let log_n_index: Var<_> = builder.eval(vkey_slots + sorted_index * four); + let size_index: Var<_> = builder.eval(log_n_index + one); + let shift_index: Var<_> = builder.eval(size_index + one); + let g_index: Var<_> = builder.eval(shift_index + one); + let log_n_felt = var2felt(builder, domain.log_n); + let size_felt = var2felt(builder, domain.size); + builder.set(&mut inputs, log_n_index, log_n_felt); + builder.set(&mut inputs, size_index, size_felt); + builder.set(&mut inputs, shift_index, domain.shift); + builder.set(&mut inputs, g_index, domain.g); + }); builder.poseidon2_hash(&inputs) } @@ -241,10 +235,7 @@ pub(crate) fn get_chip_quotient_data Execute<'a> { elf: &'a [u8], stdin: SP1Stdin, ) -> Self { - Self { - prover, - elf, - stdin, - context_builder: Default::default(), - } + Self { prover, elf, stdin, context_builder: Default::default() } } /// Execute the program on the input, consuming the built action `self`. pub fn run(self) -> Result<(SP1PublicValues, ExecutionReport)> { - let Self { - prover, - elf, - stdin, - mut context_builder, - } = self; + let Self { prover, elf, stdin, mut context_builder } = self; let context = context_builder.build(); Ok(prover.sp1_prover().execute(elf, &stdin, context)?) } @@ -73,7 +62,8 @@ impl<'a> Execute<'a> { /// Set the maximum number of cpu cycles to use for execution. /// - /// If the cycle limit is exceeded, execution will return [sp1_core::runtime::ExecutionError::ExceededCycleLimit]. + /// If the cycle limit is exceeded, execution will return + /// [sp1_core_machine::runtime::ExecutionError::ExceededCycleLimit]. pub fn max_cycles(mut self, max_cycles: u64) -> Self { self.context_builder.max_cycles(max_cycles); self @@ -127,14 +117,8 @@ impl<'a> Prove<'a> { recursion_opts, timeout, } = self; - let opts = SP1ProverOpts { - core_opts, - recursion_opts, - }; - let proof_opts = ProofOpts { - sp1_prover_opts: opts, - timeout, - }; + let opts = SP1ProverOpts { core_opts, recursion_opts }; + let proof_opts = ProofOpts { sp1_prover_opts: opts, timeout }; let context = context_builder.build(); prover.prove(pk, stdin, proof_opts, context, kind) @@ -158,6 +142,12 @@ impl<'a> Prove<'a> { self } + /// Set the proof mode to the groth16 bn254 mode. + pub fn groth16(mut self) -> Self { + self.kind = SP1ProofKind::Groth16; + self + } + /// Add a runtime [Hook](super::Hook) into the context. /// /// Hooks may be invoked from within SP1 by writing to the specified file descriptor `fd` @@ -201,7 +191,8 @@ impl<'a> Prove<'a> { /// Set the maximum number of cpu cycles to use for execution. /// - /// If the cycle limit is exceeded, execution will return [sp1_core::runtime::ExecutionError::ExceededCycleLimit]. + /// If the cycle limit is exceeded, execution will return + /// [sp1_core_machine::runtime::ExecutionError::ExceededCycleLimit]. pub fn cycle_limit(mut self, cycle_limit: u64) -> Self { self.context_builder.max_cycles(cycle_limit); self diff --git a/sdk/src/artifacts.rs b/crates/sdk/src/artifacts.rs similarity index 53% rename from sdk/src/artifacts.rs rename to crates/sdk/src/artifacts.rs index cb88316ea9..6bf52aaab4 100644 --- a/sdk/src/artifacts.rs +++ b/crates/sdk/src/artifacts.rs @@ -6,7 +6,7 @@ use indicatif::{ProgressBar, ProgressStyle}; use reqwest::Client; pub use sp1_prover::build::build_plonk_bn254_artifacts_with_dummy; -use crate::install::try_install_plonk_bn254_artifacts; +use crate::install::try_install_circuit_artifacts; /// Exports the solidity verifier for PLONK proofs to the specified output directory. /// @@ -17,19 +17,45 @@ pub fn export_solidity_plonk_bn254_verifier(output_dir: impl Into) -> R let artifacts_dir = if sp1_prover::build::sp1_dev_mode() { sp1_prover::build::plonk_bn254_artifacts_dev_dir() } else { - try_install_plonk_bn254_artifacts() + try_install_circuit_artifacts() }; - let verifier_path = artifacts_dir.join("SP1Verifier.sol"); + let verifier_path = artifacts_dir.join("SP1VerifierPlonk.sol"); if !verifier_path.exists() { - return Err(anyhow::anyhow!( - "verifier file not found at {:?}", - verifier_path - )); + return Err(anyhow::anyhow!("verifier file not found at {:?}", verifier_path)); } std::fs::create_dir_all(&output_dir).context("Failed to create output directory.")?; - let output_path = output_dir.join("SP1Verifier.sol"); + let output_path = output_dir.join("SP1VerifierPlonk.sol"); + std::fs::copy(&verifier_path, &output_path).context("Failed to copy verifier file.")?; + tracing::info!( + "exported verifier from {} to {}", + verifier_path.display(), + output_path.display() + ); + + Ok(()) +} + +/// Exports the solidity verifier for Groth16 proofs to the specified output directory. +/// +/// WARNING: If you are on development mode, this function assumes that the Groth16 artifacts have +/// already been built. +pub fn export_solidity_groth16_bn254_verifier(output_dir: impl Into) -> Result<()> { + let output_dir: PathBuf = output_dir.into(); + let artifacts_dir = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::groth16_bn254_artifacts_dev_dir() + } else { + try_install_circuit_artifacts() + }; + let verifier_path = artifacts_dir.join("SP1VerifierGroth16.sol"); + + if !verifier_path.exists() { + return Err(anyhow::anyhow!("verifier file not found at {:?}", verifier_path)); + } + + std::fs::create_dir_all(&output_dir).context("Failed to create output directory.")?; + let output_path = output_dir.join("SP1VerifierGroth16.sol"); std::fs::copy(&verifier_path, &output_path).context("Failed to copy verifier file.")?; tracing::info!( "exported verifier from {} to {}", @@ -45,14 +71,9 @@ pub async fn download_file( url: &str, file: &mut File, ) -> std::result::Result<(), String> { - let res = client - .get(url) - .send() - .await - .or(Err(format!("Failed to GET from '{}'", &url)))?; - let total_size = res - .content_length() - .ok_or(format!("Failed to get content length from '{}'", &url))?; + let res = client.get(url).send().await.or(Err(format!("Failed to GET from '{}'", &url)))?; + let total_size = + res.content_length().ok_or(format!("Failed to get content length from '{}'", &url))?; let pb = ProgressBar::new(total_size); pb.set_style(ProgressStyle::default_bar() @@ -65,8 +86,7 @@ pub async fn download_file( while let Some(item) = stream.next().await { let chunk = item.or(Err("Error while downloading file"))?; - file.write_all(&chunk) - .or(Err("Error while writing to file"))?; + file.write_all(&chunk).or(Err("Error while writing to file"))?; let new = min(downloaded + (chunk.len() as u64), total_size); downloaded = new; pb.set_position(new); @@ -76,12 +96,3 @@ pub async fn download_file( pb.finish_with_message(msg); Ok(()) } - -#[cfg(test)] -mod tests { - #[test] - fn test_verifier_export() { - crate::artifacts::export_solidity_plonk_bn254_verifier(tempfile::tempdir().unwrap().path()) - .expect("failed to export verifier"); - } -} diff --git a/crates/sdk/src/install.rs b/crates/sdk/src/install.rs new file mode 100644 index 0000000000..d0cbf87cae --- /dev/null +++ b/crates/sdk/src/install.rs @@ -0,0 +1,102 @@ +use std::{cmp::min, io::Write, path::PathBuf, process::Command}; + +use futures::StreamExt; +use indicatif::{ProgressBar, ProgressStyle}; +use reqwest::Client; +use sp1_cuda::block_on; + +use crate::SP1_CIRCUIT_VERSION; + +/// The base URL for the S3 bucket containing the ciruit artifacts. +pub const CIRCUIT_ARTIFACTS_URL_BASE: &str = "https://sp1-circuits.s3-us-east-2.amazonaws.com"; + +/// Gets the directory where the circuit artifacts are installed. +fn circuit_artifacts_dir() -> PathBuf { + dirs::home_dir().unwrap().join(".sp1").join("circuits").join(SP1_CIRCUIT_VERSION) +} + +/// Tries to install the circuit artifacts if they are not already installed. +pub fn try_install_circuit_artifacts() -> PathBuf { + let build_dir = circuit_artifacts_dir(); + + if build_dir.exists() { + println!( + "[sp1] circuit artifacts already seem to exist at {}. if you want to re-download them, delete the directory", + build_dir.display() + ); + } else { + println!( + "[sp1] circuit artifacts for version {} do not exist at {}. downloading...", + SP1_CIRCUIT_VERSION, + build_dir.display() + ); + install_circuit_artifacts(build_dir.clone()); + } + build_dir +} + +/// Install the latest circuit artifacts. +/// +/// This function will download the latest circuit artifacts from the S3 bucket and extract them +/// to the directory specified by [plonk_bn254_artifacts_dir()]. +pub fn install_circuit_artifacts(build_dir: PathBuf) { + // Create the build directory. + std::fs::create_dir_all(&build_dir).expect("failed to create build directory"); + + // Download the artifacts. + let download_url = format!("{}/{}.tar.gz", CIRCUIT_ARTIFACTS_URL_BASE, SP1_CIRCUIT_VERSION); + let mut artifacts_tar_gz_file = + tempfile::NamedTempFile::new().expect("failed to create tempfile"); + let client = Client::builder().build().expect("failed to create reqwest client"); + block_on(download_file(&client, &download_url, &mut artifacts_tar_gz_file)) + .expect("failed to download file"); + + // Extract the tarball to the build directory. + let mut res = Command::new("tar") + .args([ + "-Pxzf", + artifacts_tar_gz_file.path().to_str().unwrap(), + "-C", + build_dir.to_str().unwrap(), + ]) + .spawn() + .expect("failed to extract tarball"); + res.wait().unwrap(); + + println!("[sp1] downloaded {} to {:?}", download_url, build_dir.to_str().unwrap(),); +} + +/// The directory where the circuit artifacts will be stored. +pub fn install_circuit_artifacts_dir() -> PathBuf { + dirs::home_dir().unwrap().join(".sp1").join("circuits").join(SP1_CIRCUIT_VERSION) +} + +/// Download the file with a progress bar that indicates the progress. +pub async fn download_file( + client: &Client, + url: &str, + file: &mut tempfile::NamedTempFile, +) -> std::result::Result<(), String> { + let res = client.get(url).send().await.or(Err(format!("Failed to GET from '{}'", &url)))?; + + let total_size = + res.content_length().ok_or(format!("Failed to get content length from '{}'", &url))?; + + let pb = ProgressBar::new(total_size); + pb.set_style(ProgressStyle::default_bar() + .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap() + .progress_chars("#>-")); + + let mut downloaded: u64 = 0; + let mut stream = res.bytes_stream(); + while let Some(item) = stream.next().await { + let chunk = item.or(Err("Error while downloading file"))?; + file.write_all(&chunk).or(Err("Error while writing to file"))?; + let new = min(downloaded + (chunk.len() as u64), total_size); + downloaded = new; + pb.set_position(new); + } + pb.finish(); + + Ok(()) +} diff --git a/sdk/src/lib.rs b/crates/sdk/src/lib.rs similarity index 72% rename from sdk/src/lib.rs rename to crates/sdk/src/lib.rs index 27cda68733..d699a4c4be 100644 --- a/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -16,11 +16,13 @@ pub mod install; pub mod network; #[cfg(feature = "network")] pub use crate::network::prover::NetworkProver; +#[cfg(feature = "cuda")] +pub use crate::provers::CudaProver; pub mod proof; pub mod provers; pub mod utils { - pub use sp1_core::utils::setup_logger; + pub use sp1_core_machine::utils::setup_logger; } use cfg_if::cfg_if; @@ -29,13 +31,13 @@ pub use provers::SP1VerificationError; use sp1_prover::components::DefaultProverComponents; use std::env; -pub use provers::{LocalProver, MockProver, Prover}; +pub use provers::{CpuProver, MockProver, Prover}; -pub use sp1_core::runtime::{ExecutionReport, Hook, HookEnv, SP1Context, SP1ContextBuilder}; -use sp1_core::SP1_CIRCUIT_VERSION; +pub use sp1_core_executor::{ExecutionReport, HookEnv, SP1Context, SP1ContextBuilder}; +pub use sp1_core_machine::{io::SP1Stdin, riscv::cost::CostEstimator, SP1_CIRCUIT_VERSION}; pub use sp1_prover::{ CoreSC, HashableKey, InnerSC, OuterSC, PlonkBn254Proof, SP1Prover, SP1ProvingKey, - SP1PublicValues, SP1Stdin, SP1VerifyingKey, + SP1VerifyingKey, }; /// A client for interacting with SP1. @@ -48,7 +50,8 @@ impl ProverClient { /// Creates a new [ProverClient]. /// /// Setting the `SP1_PROVER` enviroment variable can change the prover used under the hood. - /// - `local` (default): Uses [LocalProver]. Recommended for proving end-to-end locally. + /// - `local` (default): Uses [CpuProver] or [CudaProver] if the `cuda` feature is enabled. + /// Recommended for proving end-to-end locally. /// - `mock`: Uses [MockProver]. Recommended for testing and development. /// - `network`: Uses [NetworkProver]. Recommended for outsourcing proof generation to an RPC. /// @@ -61,16 +64,17 @@ impl ProverClient { /// let client = ProverClient::new(); /// ``` pub fn new() -> Self { - match env::var("SP1_PROVER") - .unwrap_or("local".to_string()) - .to_lowercase() - .as_str() - { - "mock" => Self { - prover: Box::new(MockProver::new()), - }, + #[cfg(debug_assertions)] + panic!("sp1-sdk must be built in release mode. please compile with the --release flag."); + + #[allow(unreachable_code)] + match env::var("SP1_PROVER").unwrap_or("local".to_string()).to_lowercase().as_str() { + "mock" => Self { prover: Box::new(MockProver::new()) }, "local" => Self { - prover: Box::new(LocalProver::new()), + #[cfg(not(feature = "cuda"))] + prover: Box::new(CpuProver::new()), + #[cfg(feature = "cuda")] + prover: Box::new(CudaProver::new()), }, "network" => { cfg_if! { @@ -102,9 +106,7 @@ impl ProverClient { /// let client = ProverClient::mock(); /// ``` pub fn mock() -> Self { - Self { - prover: Box::new(MockProver::new()), - } + Self { prover: Box::new(MockProver::new()) } } /// Creates a new [ProverClient] with the local prover. @@ -120,9 +122,7 @@ impl ProverClient { /// let client = ProverClient::local(); /// ``` pub fn local() -> Self { - Self { - prover: Box::new(LocalProver::new()), - } + Self { prover: Box::new(CpuProver::new()) } } /// Creates a new [ProverClient] with the network prover. @@ -158,10 +158,10 @@ impl ProverClient { /// /// ### Examples /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Stdin, SP1Context}; + /// use sp1_sdk::{ProverClient, SP1Context, SP1Stdin}; /// /// // Load the program. - /// let elf = include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + /// let elf = include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); /// /// // Initialize the prover client. /// let client = ProverClient::new(); @@ -177,8 +177,8 @@ impl ProverClient { action::Execute::new(self.prover.as_ref(), elf, stdin) } - /// Prepare to prove the execution of the given program with the given input in the default mode. - /// The returned [action::Prove] may be configured via its methods before running. + /// Prepare to prove the execution of the given program with the given input in the default + /// mode. The returned [action::Prove] may be configured via its methods before running. /// For example, calling [action::Prove::compress] sets the mode to compressed mode. /// /// To prove, call [action::Prove::run], which returns a proof of the program's execution. @@ -188,10 +188,10 @@ impl ProverClient { /// /// ### Examples /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Stdin, SP1Context}; + /// use sp1_sdk::{ProverClient, SP1Context, SP1Stdin}; /// /// // Load the program. - /// let elf = include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + /// let elf = include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); /// /// // Initialize the prover client. /// let client = ProverClient::new(); @@ -217,7 +217,7 @@ impl ProverClient { /// ```no_run /// use sp1_sdk::{ProverClient, SP1Stdin}; /// - /// let elf = include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + /// let elf = include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); /// let client = ProverClient::new(); /// let (pk, vk) = client.setup(elf); /// let mut stdin = SP1Stdin::new(); @@ -250,7 +250,7 @@ impl ProverClient { /// ```no_run /// use sp1_sdk::{ProverClient, SP1Stdin}; /// - /// let elf = include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + /// let elf = include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); /// let client = ProverClient::new(); /// let mut stdin = SP1Stdin::new(); /// stdin.write(&10usize); @@ -270,60 +270,18 @@ impl Default for ProverClient { #[cfg(test)] mod tests { - use std::sync::atomic::{AtomicU32, Ordering}; - - use sp1_core::runtime::{hook_ecrecover, FD_ECRECOVER_HOOK}; - - use crate::{utils, ProverClient, SP1Stdin}; + use crate::{utils, CostEstimator, ProverClient, SP1Stdin}; #[test] fn test_execute() { utils::setup_logger(); let client = ProverClient::local(); let elf = - include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - client.execute(elf, stdin).run().unwrap(); - } - - #[test] - fn test_execute_new() { - // Wrap the hook and check that it was called. - let call_ct = AtomicU32::new(0); - utils::setup_logger(); - let client = ProverClient::local(); - let elf = include_bytes!("../../tests/ecrecover/elf/riscv32im-succinct-zkvm-elf"); - let stdin = SP1Stdin::new(); - client - .execute(elf, stdin) - .with_hook(FD_ECRECOVER_HOOK, |env, buf| { - call_ct.fetch_add(1, Ordering::Relaxed); - hook_ecrecover(env, buf) - }) - .run() - .unwrap(); - assert_ne!(call_ct.into_inner(), 0); - } - - #[test] - fn test_prove_new() { - // Wrap the hook and check that it was called. - let call_ct = AtomicU32::new(0); - utils::setup_logger(); - let client = ProverClient::local(); - let elf = include_bytes!("../../tests/ecrecover/elf/riscv32im-succinct-zkvm-elf"); - let stdin = SP1Stdin::new(); - let (pk, _) = client.setup(elf); - client - .prove(&pk, stdin) - .with_hook(FD_ECRECOVER_HOOK, |env, buf| { - call_ct.fetch_add(1, Ordering::Relaxed); - hook_ecrecover(env, buf) - }) - .run() - .unwrap(); - assert_ne!(call_ct.into_inner(), 0); + let (_, report) = client.execute(elf, stdin).run().unwrap(); + tracing::info!("gas = {}", report.estimate_gas()); } #[test] @@ -331,7 +289,7 @@ mod tests { fn test_execute_panic() { utils::setup_logger(); let client = ProverClient::local(); - let elf = include_bytes!("../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); + let elf = include_bytes!("../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); client.execute(elf, stdin).run().unwrap(); @@ -342,7 +300,7 @@ mod tests { fn test_cycle_limit_fail() { utils::setup_logger(); let client = ProverClient::local(); - let elf = include_bytes!("../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); + let elf = include_bytes!("../../../tests/panic/elf/riscv32im-succinct-zkvm-elf"); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); client.execute(elf, stdin).max_cycles(1).run().unwrap(); @@ -353,7 +311,7 @@ mod tests { utils::setup_logger(); let client = ProverClient::local(); let elf = - include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); @@ -366,7 +324,7 @@ mod tests { utils::setup_logger(); let client = ProverClient::mock(); let elf = - include_bytes!("../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); diff --git a/sdk/src/network/auth.rs b/crates/sdk/src/network/auth.rs similarity index 80% rename from sdk/src/network/auth.rs rename to crates/sdk/src/network/auth.rs index 0ec918d778..45354a66ba 100644 --- a/sdk/src/network/auth.rs +++ b/crates/sdk/src/network/auth.rs @@ -1,5 +1,4 @@ -use std::borrow::Cow; -use std::str::FromStr; +use std::{borrow::Cow, str::FromStr}; use alloy_sol_types::{sol, Eip712Domain, SolStruct}; use anyhow::Result; @@ -44,8 +43,8 @@ sol! { /// Handles authentication for the Succinct prover network. All interactions that could potentially /// use computational resources must be authenticated by signing a message with a secp256k1 key. /// -/// The messages themselves follow EIP-712, where the domain is "succinct" and the TypeStruct changes -/// depending on which endpoint is being used. Documentation for EIP-712 can be found at: +/// The messages themselves follow EIP-712, where the domain is "succinct" and the TypeStruct +/// changes depending on which endpoint is being used. Documentation for EIP-712 can be found at: /// https://eips.ethereum.org/EIPS/eip-712 pub struct NetworkAuth { // Holds a secp256k1 private key. @@ -88,30 +87,20 @@ impl NetworkAuth { mode: i32, version: &str, ) -> Result> { - let type_struct = CreateProof { - nonce, - deadline, - mode: mode as u32, - version: version.to_string(), - }; + let type_struct = + CreateProof { nonce, deadline, mode: mode as u32, version: version.to_string() }; self.sign_message(type_struct).await } /// Signs a message to mark a proof as ready for proof generation. pub async fn sign_submit_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = SubmitProof { - nonce, - proof_id: proof_id.to_string(), - }; + let type_struct = SubmitProof { nonce, proof_id: proof_id.to_string() }; self.sign_message(type_struct).await } /// Signs a message to claim a proof that was requested. pub async fn sign_claim_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = ClaimProof { - nonce, - proof_id: proof_id.to_string(), - }; + let type_struct = ClaimProof { nonce, proof_id: proof_id.to_string() }; self.sign_message(type_struct).await } @@ -123,22 +112,14 @@ impl NetworkAuth { reason: UnclaimReason, description: String, ) -> Result> { - let type_struct = UnclaimProof { - nonce, - proof_id, - reason: reason as u8, - description, - }; + let type_struct = UnclaimProof { nonce, proof_id, reason: reason as u8, description }; self.sign_message(type_struct).await } /// Signs a message to fulfill a proof. The proof must have been previously claimed by the /// signer first. pub async fn sign_fulfill_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = FulfillProof { - nonce, - proof_id: proof_id.to_string(), - }; + let type_struct = FulfillProof { nonce, proof_id: proof_id.to_string() }; self.sign_message(type_struct).await } } diff --git a/sdk/src/network/client.rs b/crates/sdk/src/network/client.rs similarity index 86% rename from sdk/src/network/client.rs rename to crates/sdk/src/network/client.rs index 9e789c7253..faacf41991 100644 --- a/sdk/src/network/client.rs +++ b/crates/sdk/src/network/client.rs @@ -9,9 +9,11 @@ use futures::{future::join_all, Future}; use reqwest::{Client as HttpClient, Url}; use reqwest_middleware::ClientWithMiddleware as HttpClientWithMiddleware; use serde::de::DeserializeOwned; -use sp1_prover::SP1Stdin; -use std::result::Result::Ok as StdOk; -use std::time::{SystemTime, UNIX_EPOCH}; +use sp1_core_machine::io::SP1Stdin; +use std::{ + result::Result::Ok as StdOk, + time::{SystemTime, UNIX_EPOCH}, +}; use twirp::{Client as TwirpClient, ClientError}; use crate::proto::network::{ @@ -59,19 +61,15 @@ impl NetworkClient { .build() .unwrap(); - Self { - auth, - rpc, - http: http_client.into(), - } + Self { auth, rpc, http: http_client.into() } } /// Gets the latest nonce for this auth's account. pub async fn get_nonce(&self) -> Result { let res = self - .with_error_handling(self.rpc.get_nonce(GetNonceRequest { - address: self.auth.get_address().to_vec(), - })) + .with_error_handling( + self.rpc.get_nonce(GetNonceRequest { address: self.auth.get_address().to_vec() }), + ) .await?; Ok(res.nonce) } @@ -82,15 +80,16 @@ impl NetworkClient { Ok(()) } - /// Get the status of a given proof. If the status is ProofFulfilled, the proof is also returned. + /// Get the status of a given proof. If the status is ProofFulfilled, the proof is also + /// returned. pub async fn get_proof_status( &self, proof_id: &str, ) -> Result<(GetProofStatusResponse, Option

)> { let res = self - .with_error_handling(self.rpc.get_proof_status(GetProofStatusRequest { - proof_id: proof_id.to_string(), - })) + .with_error_handling( + self.rpc.get_proof_status(GetProofStatusRequest { proof_id: proof_id.to_string() }), + ) .await .context("Failed to get proof status")?; @@ -120,9 +119,9 @@ impl NetworkClient { &self, status: ProofStatus, ) -> Result { - self.with_error_handling(self.rpc.get_proof_requests(GetProofRequestsRequest { - status: status.into(), - })) + self.with_error_handling( + self.rpc.get_proof_requests(GetProofRequestsRequest { status: status.into() }), + ) .await } @@ -135,16 +134,12 @@ impl NetworkClient { version: &str, ) -> Result { let start = SystemTime::now(); - let since_the_epoch = start - .duration_since(UNIX_EPOCH) - .expect("Invalid start time"); + let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Invalid start time"); let deadline = since_the_epoch.as_secs() + TIMEOUT.as_secs(); let nonce = self.get_nonce().await?; - let create_proof_signature = self - .auth - .sign_create_proof_message(nonce, deadline, mode.into(), version) - .await?; + let create_proof_signature = + self.auth.sign_create_proof_message(nonce, deadline, mode.into(), version).await?; let res = self .with_error_handling(self.rpc.create_proof(CreateProofRequest { @@ -166,10 +161,8 @@ impl NetworkClient { results.pop().expect("Failed to upload program")?; let nonce = self.get_nonce().await?; - let submit_proof_signature = self - .auth - .sign_submit_proof_message(nonce, &res.proof_id) - .await?; + let submit_proof_signature = + self.auth.sign_submit_proof_message(nonce, &res.proof_id).await?; self.with_error_handling(self.rpc.submit_proof(SubmitProofRequest { signature: submit_proof_signature.to_vec(), @@ -196,8 +189,8 @@ impl NetworkClient { } /// Unclaim a proof that was claimed. This should only be called if the proof has not been - /// fulfilled yet. Returns an error if the proof is not in a PROOF_CLAIMED state or if the caller - /// is not the claimer. + /// fulfilled yet. Returns an error if the proof is not in a PROOF_CLAIMED state or if the + /// caller is not the claimer. pub async fn unclaim_proof( &self, proof_id: String, @@ -226,10 +219,7 @@ impl NetworkClient { /// if the proof is not in a PROOF_CLAIMED state or if the caller is not the claimer. pub async fn fulfill_proof(&self, proof_id: &str) -> Result { let nonce = self.get_nonce().await?; - let signature = self - .auth - .sign_fulfill_proof_message(nonce, proof_id) - .await?; + let signature = self.auth.sign_fulfill_proof_message(nonce, proof_id).await?; let res = self .with_error_handling(self.rpc.fulfill_proof(FulfillProofRequest { signature, diff --git a/sdk/src/network/mod.rs b/crates/sdk/src/network/mod.rs similarity index 100% rename from sdk/src/network/mod.rs rename to crates/sdk/src/network/mod.rs diff --git a/sdk/src/network/prover.rs b/crates/sdk/src/network/prover.rs similarity index 79% rename from sdk/src/network/prover.rs rename to crates/sdk/src/network/prover.rs index 1e225404ad..cd267cc2bc 100644 --- a/sdk/src/network/prover.rs +++ b/crates/sdk/src/network/prover.rs @@ -1,27 +1,27 @@ -use std::time::Instant; -use std::{env, time::Duration}; +use std::{ + env, + time::{Duration, Instant}, +}; -use crate::install::block_on; -use crate::proto::network::ProofMode; use crate::{ network::client::{NetworkClient, DEFAULT_PROVER_NETWORK_RPC}, - proto::network::ProofStatus, - Prover, + proto::network::{ProofMode, ProofStatus}, + Prover, SP1Context, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, }; -use crate::{SP1Context, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey}; use anyhow::Result; use serde::de::DeserializeOwned; -use sp1_core::utils::SP1ProverOpts; -use sp1_prover::components::DefaultProverComponents; -use sp1_prover::{SP1Prover, SP1Stdin, SP1_CIRCUIT_VERSION}; +use sp1_core_machine::io::SP1Stdin; +use sp1_cuda::block_on; +use sp1_prover::{components::DefaultProverComponents, SP1Prover, SP1_CIRCUIT_VERSION}; +use sp1_stark::SP1ProverOpts; use tokio::time::sleep; -use crate::provers::{LocalProver, ProofOpts, ProverType}; +use crate::provers::{CpuProver, ProofOpts, ProverType}; /// An implementation of [crate::ProverClient] that can generate proofs on a remote RPC server. pub struct NetworkProver { client: NetworkClient, - local_prover: LocalProver, + local_prover: CpuProver, } impl NetworkProver { @@ -37,11 +37,8 @@ impl NetworkProver { let version = SP1_CIRCUIT_VERSION; log::info!("Client circuit version: {}", version); - let local_prover = LocalProver::new(); - Self { - client: NetworkClient::new(private_key), - local_prover, - } + let local_prover = CpuProver::new(); + Self { client: NetworkClient::new(private_key), local_prover } } /// Requests a proof from the prover network, returning the proof ID. @@ -53,19 +50,12 @@ impl NetworkProver { ) -> Result { let client = &self.client; - let skip_simulation = env::var("SKIP_SIMULATION") - .map(|val| val == "true") - .unwrap_or(false); + let skip_simulation = env::var("SKIP_SIMULATION").map(|val| val == "true").unwrap_or(false); if !skip_simulation { let (_, report) = - self.local_prover - .sp1_prover() - .execute(elf, &stdin, Default::default())?; - log::info!( - "Simulation complete, cycles: {}", - report.total_instruction_count() - ); + self.local_prover.sp1_prover().execute(elf, &stdin, Default::default())?; + log::info!("Simulation complete, cycles: {}", report.total_instruction_count()); } else { log::info!("Skipping simulation"); } @@ -75,10 +65,7 @@ impl NetworkProver { log::info!("Created {}", proof_id); if NetworkClient::rpc_url() == DEFAULT_PROVER_NETWORK_RPC { - log::info!( - "View in explorer: https://explorer.succinct.xyz/{}", - proof_id - ); + log::info!("View in explorer: https://explorer.succinct.xyz/{}", proof_id); } Ok(proof_id) } @@ -177,16 +164,9 @@ fn warn_if_not_default(opts: &SP1ProverOpts, context: &SP1Context) { tracing::warn!("custom SP1ProverOpts are currently unsupported by the network prover"); } // Exhaustive match is done to ensure we update the warnings if the types change. - let SP1Context { - hook_registry, - subproof_verifier, - .. - } = context; + let SP1Context { hook_registry, subproof_verifier, .. } = context; if hook_registry.is_some() { - tracing::warn!( - "non-default context.hook_registry will be ignored: {:?}", - hook_registry - ); + tracing::warn!("non-default context.hook_registry will be ignored: {:?}", hook_registry); tracing::warn!("custom runtime hooks are currently unsupported by the network prover"); tracing::warn!("proving may fail due to missing hooks"); } @@ -202,6 +182,7 @@ impl From for ProofMode { SP1ProofKind::Core => Self::Core, SP1ProofKind::Compressed => Self::Compressed, SP1ProofKind::Plonk => Self::Plonk, + SP1ProofKind::Groth16 => Self::Groth16, } } } diff --git a/sdk/src/proof.rs b/crates/sdk/src/proof.rs similarity index 70% rename from sdk/src/proof.rs rename to crates/sdk/src/proof.rs index 86d8939f74..d22621d7f1 100644 --- a/sdk/src/proof.rs +++ b/crates/sdk/src/proof.rs @@ -2,10 +2,11 @@ use std::{fmt::Debug, fs::File, path::Path}; use anyhow::Result; use serde::{Deserialize, Serialize}; +use sp1_core_machine::io::{SP1PublicValues, SP1Stdin}; use strum_macros::{EnumDiscriminants, EnumTryAs}; -use sp1_core::stark::{MachineVerificationError, ShardProof}; -use sp1_prover::{CoreSC, InnerSC, PlonkBn254Proof, SP1PublicValues, SP1Stdin}; +use sp1_prover::{CoreSC, Groth16Bn254Proof, InnerSC, PlonkBn254Proof}; +use sp1_stark::{MachineVerificationError, ShardProof}; /// A proof generated with SP1 of a particular proof mode. #[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, EnumTryAs)] @@ -16,6 +17,7 @@ pub enum SP1Proof { Core(Vec>), Compressed(ShardProof), Plonk(PlonkBn254Proof), + Groth16(Groth16Bn254Proof), } /// A proof generated with SP1, bundled together with stdin, public values, and the SP1 version. @@ -48,8 +50,9 @@ impl SP1ProofWithPublicValues { } } - /// For Plonk proofs, returns the proof in a byte encoding the onchain verifier accepts. - /// The bytes consist of the first four bytes of Plonk vkey hash followed by the encoded proof. + /// For Plonk or Groth16 proofs, returns the proof in a byte encoding the onchain verifier + /// accepts. The bytes consist of the first four bytes of Plonk vkey hash followed by the + /// encoded proof. pub fn bytes(&self) -> Vec { match &self.proof { SP1Proof::Plonk(plonk_proof) => { @@ -60,7 +63,15 @@ impl SP1ProofWithPublicValues { ); bytes } - _ => unimplemented!("only Plonk proofs are verifiable onchain"), + SP1Proof::Groth16(groth16_proof) => { + let mut bytes = Vec::with_capacity(4 + groth16_proof.encoded_proof.len()); + bytes.extend_from_slice(&groth16_proof.groth16_vkey_hash[..4]); + bytes.extend_from_slice( + &hex::decode(&groth16_proof.encoded_proof).expect("Invalid Groth16 proof"), + ); + bytes + } + _ => unimplemented!("only Plonk and Groth16 proofs are verifiable onchain"), } } } diff --git a/sdk/src/proto/network.rs b/crates/sdk/src/proto/network.rs similarity index 98% rename from sdk/src/proto/network.rs rename to crates/sdk/src/proto/network.rs index 5f36a2bd84..4c3dd84771 100644 --- a/sdk/src/proto/network.rs +++ b/crates/sdk/src/proto/network.rs @@ -306,6 +306,8 @@ pub enum ProofMode { Compressed = 2, /// The proof mode for a PlonK proof. Plonk = 3, + /// The proof mode for a Groth16 proof. + Groth16 = 4, } impl ProofMode { /// String value of the enum field names used in the ProtoBuf definition. @@ -318,6 +320,7 @@ impl ProofMode { ProofMode::Core => "PROOF_MODE_CORE", ProofMode::Compressed => "PROOF_MODE_COMPRESSED", ProofMode::Plonk => "PROOF_MODE_PLONK", + ProofMode::Groth16 => "PROOF_MODE_GROTH16", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -327,6 +330,7 @@ impl ProofMode { "PROOF_MODE_CORE" => Some(Self::Core), "PROOF_MODE_COMPRESSED" => Some(Self::Compressed), "PROOF_MODE_PLONK" => Some(Self::Plonk), + "PROOF_MODE_GROTH16" => Some(Self::Groth16), _ => None, } } @@ -706,27 +710,21 @@ impl NetworkServiceClient for twirp::client::Client { &self, req: GetProofStatusRequest, ) -> Result { - let url = self - .base_url - .join("network.NetworkService/GetProofStatus")?; + let url = self.base_url.join("network.NetworkService/GetProofStatus")?; self.request(url, req).await } async fn get_proof_requests( &self, req: GetProofRequestsRequest, ) -> Result { - let url = self - .base_url - .join("network.NetworkService/GetProofRequests")?; + let url = self.base_url.join("network.NetworkService/GetProofRequests")?; self.request(url, req).await } async fn get_relay_status( &self, req: GetRelayStatusRequest, ) -> Result { - let url = self - .base_url - .join("network.NetworkService/GetRelayStatus")?; + let url = self.base_url.join("network.NetworkService/GetRelayStatus")?; self.request(url, req).await } } diff --git a/crates/sdk/src/provers/cpu.rs b/crates/sdk/src/provers/cpu.rs new file mode 100644 index 0000000000..03cc8843db --- /dev/null +++ b/crates/sdk/src/provers/cpu.rs @@ -0,0 +1,127 @@ +use anyhow::Result; +use sp1_core_executor::SP1Context; +use sp1_prover::{components::DefaultProverComponents, SP1Prover, SP1Stdin}; + +use crate::{ + install::try_install_circuit_artifacts, provers::ProofOpts, Prover, SP1Proof, SP1ProofKind, + SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, +}; + +use super::ProverType; + +/// An implementation of [crate::ProverClient] that can generate end-to-end proofs locally. +pub struct CpuProver { + prover: SP1Prover, +} + +impl CpuProver { + /// Creates a new [LocalProver]. + pub fn new() -> Self { + let prover = SP1Prover::new(); + Self { prover } + } + + /// Creates a new [LocalProver] from an existing [SP1Prover]. + pub fn from_prover(prover: SP1Prover) -> Self { + Self { prover } + } +} + +impl Prover for CpuProver { + fn id(&self) -> ProverType { + ProverType::Cpu + } + + fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { + self.prover.setup(elf) + } + + fn sp1_prover(&self) -> &SP1Prover { + &self.prover + } + + fn prove<'a>( + &'a self, + pk: &SP1ProvingKey, + stdin: SP1Stdin, + opts: ProofOpts, + context: SP1Context<'a>, + kind: SP1ProofKind, + ) -> Result { + // Generate the core proof. + let proof = self.prover.prove_core(pk, &stdin, opts.sp1_prover_opts, context)?; + if kind == SP1ProofKind::Core { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Core(proof.proof.0), + stdin: proof.stdin, + public_values: proof.public_values, + sp1_version: self.version().to_string(), + }); + } + + let deferred_proofs = stdin.proofs.iter().map(|p| p.0.clone()).collect(); + let public_values = proof.public_values.clone(); + + // Generate the compressed proof. + let reduce_proof = + self.prover.compress(&pk.vk, proof, deferred_proofs, opts.sp1_prover_opts)?; + if kind == SP1ProofKind::Compressed { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Compressed(reduce_proof.proof), + stdin, + public_values, + sp1_version: self.version().to_string(), + }); + } + + // Generate the shrink proof. + let compress_proof = self.prover.shrink(reduce_proof, opts.sp1_prover_opts)?; + + // Genenerate the wrap proof. + let outer_proof = self.prover.wrap_bn254(compress_proof, opts.sp1_prover_opts)?; + + if kind == SP1ProofKind::Plonk { + let plonk_bn254_aritfacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_plonk_bn254_artifacts_dev( + self.prover.wrap_vk(), + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts() + }; + let proof = self.prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_aritfacts); + + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Plonk(proof), + stdin, + public_values, + sp1_version: self.version().to_string(), + }); + } else if kind == SP1ProofKind::Groth16 { + let groth16_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_groth16_bn254_artifacts_dev( + self.prover.wrap_vk(), + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts() + }; + + let proof = self.prover.wrap_groth16_bn254(outer_proof, &groth16_bn254_artifacts); + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Groth16(proof), + stdin, + public_values, + sp1_version: self.version().to_string(), + }); + } + + unreachable!() + } +} + +impl Default for CpuProver { + fn default() -> Self { + Self::new() + } +} diff --git a/sdk/src/provers/local.rs b/crates/sdk/src/provers/cuda.rs similarity index 51% rename from sdk/src/provers/local.rs rename to crates/sdk/src/provers/cuda.rs index c172c32193..f271530a61 100644 --- a/sdk/src/provers/local.rs +++ b/crates/sdk/src/provers/cuda.rs @@ -1,43 +1,39 @@ use anyhow::Result; -use sp1_core::runtime::SP1Context; -use sp1_prover::{components::SP1ProverComponents, SP1Prover, SP1Stdin}; -use sysinfo::System; +use sp1_cuda::SP1CudaProver; +use sp1_prover::{components::DefaultProverComponents, SP1Prover, SP1Stdin}; +use super::ProverType; use crate::{ - install::try_install_plonk_bn254_artifacts, provers::ProofOpts, Prover, SP1Proof, SP1ProofKind, - SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, + provers::{try_install_circuit_artifacts, ProofOpts}, + Prover, SP1Context, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, + SP1VerifyingKey, }; -use super::ProverType; - -/// An implementation of [crate::ProverClient] that can generate end-to-end proofs locally. -pub struct LocalProver { - prover: SP1Prover, +/// An implementation of [crate::ProverClient] that can generate proofs locally using CUDA. +pub struct CudaProver { + prover: SP1Prover, + cuda_prover: SP1CudaProver, } -impl LocalProver { - /// Creates a new [LocalProver]. +impl CudaProver { + /// Creates a new [CudaProver]. pub fn new() -> Self { let prover = SP1Prover::new(); - Self { prover } - } - - /// Creates a new [LocalProver] from an existing [SP1Prover]. - pub fn from_prover(prover: SP1Prover) -> Self { - Self { prover } + let cuda_prover = SP1CudaProver::new(); + Self { prover, cuda_prover } } } -impl Prover for LocalProver { +impl Prover for CudaProver { fn id(&self) -> ProverType { - ProverType::Local + ProverType::Cuda } fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { self.prover.setup(elf) } - fn sp1_prover(&self) -> &SP1Prover { + fn sp1_prover(&self) -> &SP1Prover { &self.prover } @@ -45,20 +41,14 @@ impl Prover for LocalProver { &'a self, pk: &SP1ProvingKey, stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, + _opts: ProofOpts, + _context: SP1Context<'a>, kind: SP1ProofKind, ) -> Result { - let total_ram_gb = System::new_all().total_memory() / 1_000_000_000; - if kind == SP1ProofKind::Plonk && total_ram_gb <= 120 { - return Err(anyhow::anyhow!( - "not enough memory to generate plonk proof. at least 128GB is required." - )); - } + tracing::warn!("opts and context are ignored for the cuda prover"); - let proof = self - .prover - .prove_core(pk, &stdin, opts.sp1_prover_opts, context)?; + // Generate the core proof. + let proof = self.cuda_prover.prove_core(pk, &stdin)?; if kind == SP1ProofKind::Core { return Ok(SP1ProofWithPublicValues { proof: SP1Proof::Core(proof.proof.0), @@ -67,11 +57,12 @@ impl Prover for LocalProver { sp1_version: self.version().to_string(), }); } + let deferred_proofs = stdin.proofs.iter().map(|p| p.0.clone()).collect(); let public_values = proof.public_values.clone(); - let reduce_proof = - self.prover - .compress(&pk.vk, proof, deferred_proofs, opts.sp1_prover_opts)?; + + // Generate the compressed proof. + let reduce_proof = self.cuda_prover.compress(&pk.vk, proof, deferred_proofs)?; if kind == SP1ProofKind::Compressed { return Ok(SP1ProofWithPublicValues { proof: SP1Proof::Compressed(reduce_proof.proof), @@ -80,10 +71,12 @@ impl Prover for LocalProver { sp1_version: self.version().to_string(), }); } - let compress_proof = self.prover.shrink(reduce_proof, opts.sp1_prover_opts)?; - let outer_proof = self - .prover - .wrap_bn254(compress_proof, opts.sp1_prover_opts)?; + + // Generate the shrink proof. + let compress_proof = self.cuda_prover.shrink(reduce_proof)?; + + // Genenerate the wrap proof. + let outer_proof = self.cuda_prover.wrap_bn254(compress_proof)?; let plonk_bn254_aritfacts = if sp1_prover::build::sp1_dev_mode() { sp1_prover::build::try_build_plonk_bn254_artifacts_dev( @@ -91,11 +84,9 @@ impl Prover for LocalProver { &outer_proof.proof, ) } else { - try_install_plonk_bn254_artifacts() + try_install_circuit_artifacts() }; - let proof = self - .prover - .wrap_plonk_bn254(outer_proof, &plonk_bn254_aritfacts); + let proof = self.prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_aritfacts); if kind == SP1ProofKind::Plonk { return Ok(SP1ProofWithPublicValues { proof: SP1Proof::Plonk(proof), @@ -104,11 +95,12 @@ impl Prover for LocalProver { sp1_version: self.version().to_string(), }); } + unreachable!() } } -impl Default for LocalProver { +impl Default for CudaProver { fn default() -> Self { Self::new() } diff --git a/sdk/src/provers/mock.rs b/crates/sdk/src/provers/mock.rs similarity index 75% rename from sdk/src/provers/mock.rs rename to crates/sdk/src/provers/mock.rs index 893643ba6b..d4d2467045 100644 --- a/sdk/src/provers/mock.rs +++ b/crates/sdk/src/provers/mock.rs @@ -1,5 +1,8 @@ #![allow(unused_variables)] use hashbrown::HashMap; +use sp1_core_executor::SP1Context; +use sp1_core_machine::io::SP1Stdin; +use sp1_stark::{ShardCommitment, ShardOpenedValues, ShardProof}; use crate::{ Prover, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerificationError, @@ -9,13 +12,10 @@ use anyhow::Result; use p3_baby_bear::BabyBear; use p3_field::{AbstractField, PrimeField}; use p3_fri::{FriProof, TwoAdicFriPcsProof}; -use sp1_core::{ - runtime::SP1Context, - stark::{ShardCommitment, ShardOpenedValues, ShardProof}, -}; use sp1_prover::{ - components::DefaultProverComponents, verify::verify_plonk_bn254_public_inputs, HashableKey, - PlonkBn254Proof, SP1Prover, SP1Stdin, + components::DefaultProverComponents, + verify::{verify_groth16_bn254_public_inputs, verify_plonk_bn254_public_inputs}, + Groth16Bn254Proof, HashableKey, PlonkBn254Proof, SP1Prover, }; use super::{ProofOpts, ProverType}; @@ -108,6 +108,23 @@ impl Prover for MockProver { sp1_version: self.version().to_string(), }) } + SP1ProofKind::Groth16 => { + let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; + Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Groth16(Groth16Bn254Proof { + public_inputs: [ + pk.vk.hash_bn254().as_canonical_biguint().to_string(), + public_values.hash().to_string(), + ], + encoded_proof: "".to_string(), + raw_proof: "".to_string(), + groth16_vkey_hash: [0; 32], + }), + stdin, + public_values, + sp1_version: self.version().to_string(), + }) + } } } @@ -121,6 +138,10 @@ impl Prover for MockProver { verify_plonk_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) .map_err(SP1VerificationError::Plonk) } + SP1Proof::Groth16(Groth16Bn254Proof { public_inputs, .. }) => { + verify_groth16_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) + .map_err(SP1VerificationError::Groth16) + } _ => Ok(()), } } diff --git a/sdk/src/provers/mod.rs b/crates/sdk/src/provers/mod.rs similarity index 64% rename from sdk/src/provers/mod.rs rename to crates/sdk/src/provers/mod.rs index 51ab930eb9..34152d8460 100644 --- a/sdk/src/provers/mod.rs +++ b/crates/sdk/src/provers/mod.rs @@ -1,33 +1,34 @@ -mod local; +mod cpu; +#[cfg(feature = "cuda")] +mod cuda; mod mock; -use anyhow::Result; -pub use local::LocalProver; +pub use cpu::CpuProver; +#[cfg(feature = "cuda")] +pub use cuda::CudaProver; pub use mock::MockProver; -use sp1_core::runtime::SP1Context; -use sp1_core::stark::MachineVerificationError; -use sp1_core::utils::SP1ProverOpts; -use sp1_core::SP1_CIRCUIT_VERSION; -use sp1_prover::components::SP1ProverComponents; -use sp1_prover::CoreSC; -use sp1_prover::InnerSC; -use sp1_prover::SP1CoreProofData; -use sp1_prover::SP1Prover; -use sp1_prover::SP1ReduceProof; -use sp1_prover::{SP1ProvingKey, SP1Stdin, SP1VerifyingKey}; + +use anyhow::Result; +use sp1_core_executor::SP1Context; +use sp1_core_machine::{io::SP1Stdin, SP1_CIRCUIT_VERSION}; +use sp1_prover::{ + components::SP1ProverComponents, CoreSC, InnerSC, SP1CoreProofData, SP1Prover, SP1ProvingKey, + SP1ReduceProof, SP1VerifyingKey, +}; +use sp1_stark::{MachineVerificationError, SP1ProverOpts}; use std::time::Duration; use strum_macros::EnumString; use thiserror::Error; -use crate::install::try_install_plonk_bn254_artifacts; -use crate::SP1Proof; -use crate::SP1ProofKind; -use crate::SP1ProofWithPublicValues; +use crate::{ + install::try_install_circuit_artifacts, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, +}; /// The type of prover. #[derive(Debug, PartialEq, EnumString)] pub enum ProverType { - Local, + Cpu, + Cuda, Mock, Network, } @@ -51,6 +52,8 @@ pub enum SP1VerificationError { Recursion(MachineVerificationError), #[error("Plonk verification error: {0}")] Plonk(anyhow::Error), + #[error("Groth16 verification error: {0}")] + Groth16(anyhow::Error), } /// An implementation of [crate::ProverClient]. @@ -84,32 +87,43 @@ pub trait Prover: Send + Sync { vkey: &SP1VerifyingKey, ) -> Result<(), SP1VerificationError> { if bundle.sp1_version != self.version() { - return Err(SP1VerificationError::VersionMismatch( - bundle.sp1_version.clone(), - )); + return Err(SP1VerificationError::VersionMismatch(bundle.sp1_version.clone())); } - match bundle.proof.clone() { + match &bundle.proof { SP1Proof::Core(proof) => self .sp1_prover() - .verify(&SP1CoreProofData(proof), vkey) + .verify(&SP1CoreProofData(proof.clone()), vkey) .map_err(SP1VerificationError::Core), SP1Proof::Compressed(proof) => self .sp1_prover() - .verify_compressed(&SP1ReduceProof { proof }, vkey) + .verify_compressed(&SP1ReduceProof { proof: proof.clone() }, vkey) .map_err(SP1VerificationError::Recursion), SP1Proof::Plonk(proof) => self .sp1_prover() .verify_plonk_bn254( - &proof, + proof, vkey, &bundle.public_values, &if sp1_prover::build::sp1_dev_mode() { sp1_prover::build::plonk_bn254_artifacts_dev_dir() } else { - try_install_plonk_bn254_artifacts() + try_install_circuit_artifacts() }, ) .map_err(SP1VerificationError::Plonk), + SP1Proof::Groth16(proof) => self + .sp1_prover() + .verify_groth16_bn254( + proof, + vkey, + &bundle.public_values, + &if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::groth16_bn254_artifacts_dev_dir() + } else { + try_install_circuit_artifacts() + }, + ) + .map_err(SP1VerificationError::Groth16), } } } diff --git a/crates/stark/CHANGELOG.md b/crates/stark/CHANGELOG.md new file mode 100644 index 0000000000..2dd2a4f9b1 --- /dev/null +++ b/crates/stark/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.0-rc1](https://github.com/succinctlabs/sp1/releases/tag/sp1-stark-v1.2.0-rc1) - 2024-08-23 + +### Added + +- gas ([#1354](https://github.com/succinctlabs/sp1/pull/1354)) + +### Fixed + +- fix fptower tests +- fix imports + +### Other + +- resolve merge conflicts between dev and experimental +- refactor + cleanup core crates diff --git a/crates/stark/Cargo.toml b/crates/stark/Cargo.toml new file mode 100644 index 0000000000..e9c76632e1 --- /dev/null +++ b/crates/stark/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "sp1-stark" +description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." +readme = "../../README.md" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = { workspace = true } +categories = { workspace = true } + +[dependencies] +# sp1 +sp1-derive = { workspace = true } +sp1-primitives = { workspace = true } + +# p3 +p3-air = { workspace = true } +p3-field = { workspace = true } +p3-matrix = { workspace = true } +p3-uni-stark = { workspace = true } +p3-util = { workspace = true } +p3-challenger = { workspace = true } +p3-commit = { workspace = true } +p3-maybe-rayon = { workspace = true, features = ["parallel"] } +p3-baby-bear = { workspace = true } +p3-dft = { workspace = true } +p3-fri = { workspace = true } +p3-merkle-tree = { workspace = true } +p3-symmetric = { workspace = true } +p3-poseidon2 = { workspace = true } + +# misc +serde = { version = "1.0.207", features = ["derive"] } +hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] } +itertools = "0.13.0" +tracing = "0.1.40" +rayon-scan = "0.1.1" +arrayref = "0.3.8" + +[dev-dependencies] +sp1-zkvm = { workspace = true } diff --git a/crates/stark/src/air/builder.rs b/crates/stark/src/air/builder.rs new file mode 100644 index 0000000000..16d41e1c54 --- /dev/null +++ b/crates/stark/src/air/builder.rs @@ -0,0 +1,362 @@ +use std::{array, iter::once}; + +use itertools::Itertools; +use p3_air::{AirBuilder, AirBuilderWithPublicValues, FilteredAirBuilder, PermutationAirBuilder}; +use p3_field::{AbstractField, Field}; +use p3_uni_stark::{ + ProverConstraintFolder, StarkGenericConfig, SymbolicAirBuilder, VerifierConstraintFolder, +}; + +use super::{interaction::AirInteraction, BinomialExtension}; +use crate::{lookup::InteractionKind, Word}; + +/// A builder that can send and receive messages (or interactions) with other AIRs. +pub trait MessageBuilder { + /// Sends a message. + fn send(&mut self, message: M); + + /// Receives a message. + fn receive(&mut self, message: M); +} + +/// A message builder for which sending and receiving messages is a no-op. +pub trait EmptyMessageBuilder: AirBuilder {} + +impl MessageBuilder for AB { + fn send(&mut self, _message: M) {} + + fn receive(&mut self, _message: M) {} +} + +/// A trait which contains basic methods for building an AIR. +pub trait BaseAirBuilder: AirBuilder + MessageBuilder> { + /// Returns a sub-builder whose constraints are enforced only when `condition` is not one. + fn when_not>(&mut self, condition: I) -> FilteredAirBuilder { + self.when_ne(condition, Self::F::one()) + } + + /// Asserts that an iterator of expressions are all equal. + fn assert_all_eq, I2: Into>( + &mut self, + left: impl IntoIterator, + right: impl IntoIterator, + ) { + for (left, right) in left.into_iter().zip_eq(right) { + self.assert_eq(left, right); + } + } + + /// Asserts that an iterator of expressions are all zero. + fn assert_all_zero>(&mut self, iter: impl IntoIterator) { + iter.into_iter().for_each(|expr| self.assert_zero(expr)); + } + + /// Will return `a` if `condition` is 1, else `b`. This assumes that `condition` is already + /// checked to be a boolean. + #[inline] + fn if_else( + &mut self, + condition: impl Into + Clone, + a: impl Into + Clone, + b: impl Into + Clone, + ) -> Self::Expr { + condition.clone().into() * a.into() + (Self::Expr::one() - condition.into()) * b.into() + } + + /// Index an array of expressions using an index bitmap. This function assumes that the + /// `EIndex` type is a boolean and that `index_bitmap`'s entries sum to 1. + fn index_array( + &mut self, + array: &[impl Into + Clone], + index_bitmap: &[impl Into + Clone], + ) -> Self::Expr { + let mut result = Self::Expr::zero(); + + for (value, i) in array.iter().zip_eq(index_bitmap) { + result += value.clone().into() * i.clone().into(); + } + + result + } +} + +/// A trait which contains methods for byte interactions in an AIR. +pub trait ByteAirBuilder: BaseAirBuilder { + /// Sends a byte operation to be processed. + #[allow(clippy::too_many_arguments)] + fn send_byte( + &mut self, + opcode: impl Into, + a: impl Into, + b: impl Into, + c: impl Into, + shard: impl Into, + channel: impl Into, + multiplicity: impl Into, + ) { + self.send_byte_pair(opcode, a, Self::Expr::zero(), b, c, shard, channel, multiplicity); + } + + /// Sends a byte operation with two outputs to be processed. + #[allow(clippy::too_many_arguments)] + fn send_byte_pair( + &mut self, + opcode: impl Into, + a1: impl Into, + a2: impl Into, + b: impl Into, + c: impl Into, + shard: impl Into, + channel: impl Into, + multiplicity: impl Into, + ) { + self.send(AirInteraction::new( + vec![ + opcode.into(), + a1.into(), + a2.into(), + b.into(), + c.into(), + shard.into(), + channel.into(), + ], + multiplicity.into(), + InteractionKind::Byte, + )); + } + + /// Receives a byte operation to be processed. + #[allow(clippy::too_many_arguments)] + fn receive_byte( + &mut self, + opcode: impl Into, + a: impl Into, + b: impl Into, + c: impl Into, + shard: impl Into, + channel: impl Into, + multiplicity: impl Into, + ) { + self.receive_byte_pair(opcode, a, Self::Expr::zero(), b, c, shard, channel, multiplicity); + } + + /// Receives a byte operation with two outputs to be processed. + #[allow(clippy::too_many_arguments)] + fn receive_byte_pair( + &mut self, + opcode: impl Into, + a1: impl Into, + a2: impl Into, + b: impl Into, + c: impl Into, + shard: impl Into, + channel: impl Into, + multiplicity: impl Into, + ) { + self.receive(AirInteraction::new( + vec![ + opcode.into(), + a1.into(), + a2.into(), + b.into(), + c.into(), + shard.into(), + channel.into(), + ], + multiplicity.into(), + InteractionKind::Byte, + )); + } +} + +/// A trait which contains methods related to ALU interactions in an AIR. +pub trait AluAirBuilder: BaseAirBuilder { + /// Sends an ALU operation to be processed. + #[allow(clippy::too_many_arguments)] + fn send_alu( + &mut self, + opcode: impl Into, + a: Word>, + b: Word>, + c: Word>, + shard: impl Into, + channel: impl Into, + nonce: impl Into, + multiplicity: impl Into, + ) { + let values = once(opcode.into()) + .chain(a.0.into_iter().map(Into::into)) + .chain(b.0.into_iter().map(Into::into)) + .chain(c.0.into_iter().map(Into::into)) + .chain(once(shard.into())) + .chain(once(channel.into())) + .chain(once(nonce.into())) + .collect(); + + self.send(AirInteraction::new(values, multiplicity.into(), InteractionKind::Alu)); + } + + /// Receives an ALU operation to be processed. + #[allow(clippy::too_many_arguments)] + fn receive_alu( + &mut self, + opcode: impl Into, + a: Word>, + b: Word>, + c: Word>, + shard: impl Into, + channel: impl Into, + nonce: impl Into, + multiplicity: impl Into, + ) { + let values = once(opcode.into()) + .chain(a.0.into_iter().map(Into::into)) + .chain(b.0.into_iter().map(Into::into)) + .chain(c.0.into_iter().map(Into::into)) + .chain(once(shard.into())) + .chain(once(channel.into())) + .chain(once(nonce.into())) + .collect(); + + self.receive(AirInteraction::new(values, multiplicity.into(), InteractionKind::Alu)); + } + + /// Sends an syscall operation to be processed (with "ECALL" opcode). + #[allow(clippy::too_many_arguments)] + fn send_syscall( + &mut self, + shard: impl Into + Clone, + channel: impl Into + Clone, + clk: impl Into + Clone, + nonce: impl Into + Clone, + syscall_id: impl Into + Clone, + arg1: impl Into + Clone, + arg2: impl Into + Clone, + multiplicity: impl Into, + ) { + self.send(AirInteraction::new( + vec![ + shard.clone().into(), + channel.clone().into(), + clk.clone().into(), + nonce.clone().into(), + syscall_id.clone().into(), + arg1.clone().into(), + arg2.clone().into(), + ], + multiplicity.into(), + InteractionKind::Syscall, + )); + } + + /// Receives a syscall operation to be processed. + #[allow(clippy::too_many_arguments)] + fn receive_syscall( + &mut self, + shard: impl Into + Clone, + channel: impl Into + Clone, + clk: impl Into + Clone, + nonce: impl Into + Clone, + syscall_id: impl Into + Clone, + arg1: impl Into + Clone, + arg2: impl Into + Clone, + multiplicity: impl Into, + ) { + self.receive(AirInteraction::new( + vec![ + shard.clone().into(), + channel.clone().into(), + clk.clone().into(), + nonce.clone().into(), + syscall_id.clone().into(), + arg1.clone().into(), + arg2.clone().into(), + ], + multiplicity.into(), + InteractionKind::Syscall, + )); + } +} + +/// A builder that can operation on extension elements. +pub trait ExtensionAirBuilder: BaseAirBuilder { + /// Asserts that the two field extensions are equal. + fn assert_ext_eq>( + &mut self, + left: BinomialExtension, + right: BinomialExtension, + ) { + for (left, right) in left.0.into_iter().zip(right.0) { + self.assert_eq(left, right); + } + } + + /// Checks if an extension element is a base element. + fn assert_is_base_element + Clone>( + &mut self, + element: BinomialExtension, + ) { + let base_slice = element.as_base_slice(); + let degree = base_slice.len(); + base_slice[1..degree].iter().for_each(|coeff| { + self.assert_zero(coeff.clone().into()); + }); + } + + /// Performs an if else on extension elements. + fn if_else_ext( + &mut self, + condition: impl Into + Clone, + a: BinomialExtension + Clone>, + b: BinomialExtension + Clone>, + ) -> BinomialExtension { + BinomialExtension(array::from_fn(|i| { + self.if_else(condition.clone(), a.0[i].clone(), b.0[i].clone()) + })) + } +} + +/// A builder that implements a permutation argument. +pub trait MultiTableAirBuilder: PermutationAirBuilder { + /// The type of the cumulative sum. + type Sum: Into; + + /// Returns the cumulative sum of the permutation. + fn cumulative_sum(&self) -> Self::Sum; +} + +/// A trait that contains the common helper methods for building `SP1 recursion` and SP1 machine +/// AIRs. +pub trait MachineAirBuilder: + BaseAirBuilder + ExtensionAirBuilder + AirBuilderWithPublicValues +{ +} + +/// A trait which contains all helper methods for building SP1 machine AIRs. +pub trait SP1AirBuilder: MachineAirBuilder + ByteAirBuilder + AluAirBuilder {} + +impl<'a, AB: AirBuilder + MessageBuilder, M> MessageBuilder for FilteredAirBuilder<'a, AB> { + fn send(&mut self, message: M) { + self.inner.send(message); + } + + fn receive(&mut self, message: M) { + self.inner.receive(message); + } +} + +impl>> BaseAirBuilder for AB {} +impl ByteAirBuilder for AB {} +impl AluAirBuilder for AB {} + +impl ExtensionAirBuilder for AB {} +impl MachineAirBuilder for AB {} +impl SP1AirBuilder for AB {} + +impl<'a, SC: StarkGenericConfig> EmptyMessageBuilder for ProverConstraintFolder<'a, SC> {} +impl<'a, SC: StarkGenericConfig> EmptyMessageBuilder for VerifierConstraintFolder<'a, SC> {} +impl EmptyMessageBuilder for SymbolicAirBuilder {} + +#[cfg(debug_assertions)] +#[cfg(not(doctest))] +impl<'a, F: Field> EmptyMessageBuilder for p3_uni_stark::DebugConstraintBuilder<'a, F> {} diff --git a/core/src/air/extension.rs b/crates/stark/src/air/extension.rs similarity index 62% rename from core/src/air/extension.rs rename to crates/stark/src/air/extension.rs index bac5907092..0f810a026d 100644 --- a/core/src/air/extension.rs +++ b/crates/stark/src/air/extension.rs @@ -6,26 +6,31 @@ use p3_field::{ }; use sp1_derive::AlignedBorrow; -const DEGREE: usize = 4; +const D: usize = 4; +/// A binomial extension element represented over a generic type `T`. #[derive(AlignedBorrow, Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] #[repr(C)] -pub struct BinomialExtension(pub [T; DEGREE]); +pub struct BinomialExtension(pub [T; D]); impl BinomialExtension { + /// Creates a new binomial extension element from a base element. pub fn from_base(b: T) -> Self where T: AbstractField, { - let mut arr: [T; DEGREE] = core::array::from_fn(|_| T::zero()); + let mut arr: [T; D] = core::array::from_fn(|_| T::zero()); arr[0] = b; Self(arr) } + /// Returns a reference to the underlying slice. pub const fn as_base_slice(&self) -> &[T] { &self.0 } + /// Creates a new binomial extension element from a binomial extension element. + #[allow(clippy::needless_pass_by_value)] pub fn from + Clone>(from: BinomialExtension) -> Self { BinomialExtension(core::array::from_fn(|i| from.0[i].clone().into())) } @@ -35,9 +40,7 @@ impl + Clone> Add for BinomialExtension { type Output = Self; fn add(self, rhs: Self) -> Self::Output { - Self(core::array::from_fn(|i| { - self.0[i].clone() + rhs.0[i].clone() - })) + Self(core::array::from_fn(|i| self.0[i].clone() + rhs.0[i].clone())) } } @@ -45,9 +48,7 @@ impl + Clone> Sub for BinomialExtension { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { - Self(core::array::from_fn(|i| { - self.0[i].clone() - rhs.0[i].clone() - })) + Self(core::array::from_fn(|i| self.0[i].clone() - rhs.0[i].clone())) } } @@ -58,10 +59,10 @@ impl + Mul + AbstractField> Mul for BinomialExten let mut result = [T::zero(), T::zero(), T::zero(), T::zero()]; let w = T::from_canonical_u32(11); - for i in 0..DEGREE { - for j in 0..DEGREE { - if i + j >= DEGREE { - result[i + j - DEGREE] += w.clone() * self.0[i].clone() * rhs.0[j].clone(); + for i in 0..D { + for j in 0..D { + if i + j >= D { + result[i + j - D] += w.clone() * self.0[i].clone() * rhs.0[j].clone(); } else { result[i + j] += self.0[i].clone() * rhs.0[j].clone(); } @@ -74,7 +75,7 @@ impl + Mul + AbstractField> Mul for BinomialExten impl Div for BinomialExtension where - F: BinomiallyExtendable, + F: BinomiallyExtendable, { type Output = Self; @@ -88,13 +89,23 @@ where impl BinomialExtension where - F: BinomiallyExtendable, + F: BinomiallyExtendable<4>, { + /// Returns the multiplicative inverse of the element. + #[must_use] pub fn inverse(&self) -> Self { let p3_ef = BinomialExtensionField::from_base_slice(&self.0); let p3_ef_inverse = p3_ef.inverse(); Self(p3_ef_inverse.as_base_slice().try_into().unwrap()) } + + /// Returns the multiplicative inverse of the element, if it exists. + #[must_use] + pub fn try_inverse(&self) -> Option { + let p3_ef = BinomialExtensionField::from_base_slice(&self.0); + let p3_ef_inverse = p3_ef.try_inverse()?; + Some(Self(p3_ef_inverse.as_base_slice().try_into().unwrap())) + } } impl Neg for BinomialExtension { @@ -105,21 +116,21 @@ impl Neg for BinomialExtension { } } -impl From> for BinomialExtension +impl From> for BinomialExtension where AF: AbstractField + Copy, - AF::F: BinomiallyExtendable, + AF::F: BinomiallyExtendable, { - fn from(value: BinomialExtensionField) -> Self { - let arr: [AF; DEGREE] = value.as_base_slice().try_into().unwrap(); + fn from(value: BinomialExtensionField) -> Self { + let arr: [AF; D] = value.as_base_slice().try_into().unwrap(); Self(arr) } } -impl From> for BinomialExtensionField +impl From> for BinomialExtensionField where AF: AbstractField + Copy, - AF::F: BinomiallyExtendable, + AF::F: BinomiallyExtendable, { fn from(value: BinomialExtension) -> Self { BinomialExtensionField::from_base_slice(&value.0) @@ -128,7 +139,7 @@ where impl IntoIterator for BinomialExtension { type Item = T; - type IntoIter = core::array::IntoIter; + type IntoIter = core::array::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() diff --git a/core/src/air/interaction.rs b/crates/stark/src/air/interaction.rs similarity index 61% rename from core/src/air/interaction.rs rename to crates/stark/src/air/interaction.rs index 37150c99d3..739084df4f 100644 --- a/core/src/air/interaction.rs +++ b/crates/stark/src/air/interaction.rs @@ -2,18 +2,17 @@ use crate::lookup::InteractionKind; /// An interaction is a cross-table lookup. pub struct AirInteraction { + /// The values of the interaction. pub values: Vec, + /// The multiplicity of the interaction. pub multiplicity: E, + /// The kind of interaction. pub kind: InteractionKind, } impl AirInteraction { - /// Create a new interaction. + /// Create a new [`AirInteraction`]. pub const fn new(values: Vec, multiplicity: E, kind: InteractionKind) -> Self { - Self { - values, - multiplicity, - kind, - } + Self { values, multiplicity, kind } } } diff --git a/core/src/air/machine.rs b/crates/stark/src/air/machine.rs similarity index 83% rename from core/src/air/machine.rs rename to crates/stark/src/air/machine.rs index a897ef5b5b..f80a1dadad 100644 --- a/core/src/air/machine.rs +++ b/crates/stark/src/air/machine.rs @@ -2,7 +2,7 @@ use p3_air::BaseAir; use p3_field::Field; use p3_matrix::dense::RowMajorMatrix; -use crate::{runtime::Program, stark::MachineRecord}; +use crate::MachineRecord; pub use sp1_derive::MachineAir; @@ -11,6 +11,7 @@ pub trait MachineAir: BaseAir + 'static + Send + Sync { /// The execution record containing events for producing the air trace. type Record: MachineRecord; + /// The program that defines the control flow of the machine. type Program: MachineProgram; /// A unique identifier for this AIR as part of a machine. @@ -19,8 +20,8 @@ pub trait MachineAir: BaseAir + 'static + Send + Sync { /// Generate the trace for a given execution record. /// /// - `input` is the execution record containing the events to be written to the trace. - /// - `output` is the execution record containing events that the `MachineAir` can add to - /// the record such as byte lookup requests. + /// - `output` is the execution record containing events that the `MachineAir` can add to the + /// record such as byte lookup requests. fn generate_trace(&self, input: &Self::Record, output: &mut Self::Record) -> RowMajorMatrix; /// Generate the dependencies for a given execution record. @@ -42,12 +43,8 @@ pub trait MachineAir: BaseAir + 'static + Send + Sync { } } +/// A program that defines the control flow of a machine through a program counter. pub trait MachineProgram: Send + Sync { + /// Gets the starting program counter. fn pc_start(&self) -> F; } - -impl MachineProgram for Program { - fn pc_start(&self) -> F { - F::from_canonical_u32(self.pc_start) - } -} diff --git a/core/src/air/mod.rs b/crates/stark/src/air/mod.rs similarity index 87% rename from core/src/air/mod.rs rename to crates/stark/src/air/mod.rs index 160487b789..91ed694cd9 100644 --- a/core/src/air/mod.rs +++ b/crates/stark/src/air/mod.rs @@ -1,3 +1,5 @@ +//! Building blocks for defining AIRs. + mod builder; mod extension; mod interaction; @@ -5,7 +7,6 @@ mod machine; mod polynomial; mod public_values; mod sub_builder; -mod word; pub use builder::*; pub use extension::*; @@ -14,4 +15,3 @@ pub use machine::*; pub use polynomial::*; pub use public_values::*; pub use sub_builder::*; -pub use word::*; diff --git a/crates/stark/src/air/polynomial.rs b/crates/stark/src/air/polynomial.rs new file mode 100644 index 0000000000..40f5fdbe84 --- /dev/null +++ b/crates/stark/src/air/polynomial.rs @@ -0,0 +1,276 @@ +use core::{ + fmt::Debug, + ops::{Add, AddAssign, Mul, Neg, Sub}, +}; +use std::slice::Iter; + +use itertools::Itertools; +use p3_field::{AbstractExtensionField, AbstractField, Field}; + +/// A polynomial represented as a vector of coefficients. +#[derive(Debug, Clone)] +pub struct Polynomial { + coefficients: Vec, +} + +impl Polynomial { + /// Create a new polynomial from a vector of coefficients. + #[must_use] + pub const fn new(coefficients: Vec) -> Self { + Self { coefficients } + } + + /// Create a new polynomial from a slice of coefficients. + pub fn from_coefficients(coefficients: &[T]) -> Self + where + T: Clone, + { + Self { coefficients: coefficients.to_vec() } + } + + /// Gets the coefficients of the polynomial. + #[must_use] + pub fn as_coefficients(self) -> Vec { + self.coefficients + } + + /// Gets the coefficients of the polynomial. + #[must_use] + pub fn coefficients(&self) -> &[T] { + &self.coefficients + } + + /// Gets the degree of the polynomial. + #[must_use] + pub fn degree(&self) -> usize { + self.coefficients.len() - 1 + } + + /// Evaluates the polynomial at a given point. + #[allow(clippy::needless_pass_by_value)] + pub fn eval>(&self, x: S) -> S + where + T: AbstractField, + { + let powers = x.powers(); + self.coefficients.iter().zip(powers).map(|(c, x)| x * c.clone()).sum() + } + + /// Computes the root quotient of the polynomial. + #[must_use] + pub fn root_quotient(&self, r: T) -> Self + where + T: Field, + { + let len = self.coefficients.len(); + let mut result = Vec::with_capacity(len - 1); + let r_inv = r.inverse(); + + result.push(-self.coefficients[0] * r_inv); + for i in 1..len - 1 { + let element = result[i - 1] - self.coefficients[i]; + result.push(element * r_inv); + } + Self { coefficients: result } + } +} + +impl FromIterator for Polynomial { + fn from_iter>(iter: I) -> Self { + Self { coefficients: iter.into_iter().collect() } + } +} + +impl + Clone> Add for Polynomial { + type Output = Self; + + fn add(self, other: Self) -> Self { + self + &other + } +} + +impl + Clone> Add for &Polynomial { + type Output = Polynomial; + + fn add(self, other: Self) -> Polynomial { + self.coefficients + .iter() + .zip_longest(other.coefficients.iter()) + .map(|x| match x { + itertools::EitherOrBoth::Both(a, b) => a.clone() + b.clone(), + itertools::EitherOrBoth::Left(a) => a.clone(), + itertools::EitherOrBoth::Right(b) => b.clone(), + }) + .collect() + } +} + +impl + Clone> Add<&Polynomial> for Polynomial { + type Output = Polynomial; + + fn add(self, other: &Polynomial) -> Polynomial { + self.coefficients + .iter() + .zip_longest(other.coefficients.iter()) + .map(|x| match x { + itertools::EitherOrBoth::Both(a, b) => a.clone() + b.clone(), + itertools::EitherOrBoth::Left(a) => a.clone(), + itertools::EitherOrBoth::Right(b) => b.clone(), + }) + .collect() + } +} + +impl + Add + AddAssign + Clone> Add for Polynomial { + type Output = Polynomial; + + fn add(self, other: T) -> Polynomial { + let mut coefficients = self.coefficients; + coefficients[0] += other; + Self::new(coefficients) + } +} + +impl + Add + Add + Clone> Add for &Polynomial { + type Output = Polynomial; + + fn add(self, other: T) -> Polynomial { + let mut coefficients = self.coefficients.clone(); + coefficients[0] = coefficients[0].clone() + other; + Polynomial::new(coefficients) + } +} + +impl> Neg for Polynomial { + type Output = Self; + + fn neg(self) -> Self { + Self::new(self.coefficients.into_iter().map(|x| -x).collect()) + } +} + +impl + Neg + Clone> Sub for Polynomial { + type Output = Self; + + fn sub(self, other: Self) -> Self { + self - &other + } +} + +impl + Neg + Clone> Sub<&Polynomial> for Polynomial { + type Output = Polynomial; + + fn sub(self, other: &Polynomial) -> Polynomial { + Polynomial::new( + self.coefficients + .iter() + .zip_longest(other.coefficients.iter()) + .map(|x| match x { + itertools::EitherOrBoth::Both(a, b) => a.clone() - b.clone(), + itertools::EitherOrBoth::Left(a) => a.clone(), + itertools::EitherOrBoth::Right(b) => -b.clone(), + }) + .collect(), + ) + } +} + +impl + Neg + Clone> Sub for &Polynomial { + type Output = Polynomial; + + fn sub(self, other: Self) -> Polynomial { + Polynomial::new( + self.coefficients + .iter() + .zip_longest(other.coefficients.iter()) + .map(|x| match x { + itertools::EitherOrBoth::Both(a, b) => a.clone() - b.clone(), + itertools::EitherOrBoth::Left(a) => a.clone(), + itertools::EitherOrBoth::Right(b) => -b.clone(), + }) + .collect(), + ) + } +} + +impl Mul for Polynomial { + type Output = Self; + + fn mul(self, other: Self) -> Self { + let mut result = vec![T::zero(); self.coefficients.len() + other.coefficients.len() - 1]; + for (i, a) in self.coefficients.into_iter().enumerate() { + for (j, b) in other.coefficients.iter().enumerate() { + result[i + j] = result[i + j].clone() + a.clone() * b.clone(); + } + } + Self::new(result) + } +} + +impl Mul for &Polynomial { + type Output = Polynomial; + + fn mul(self, other: Self) -> Polynomial { + let mut result = vec![T::zero(); self.coefficients.len() + other.coefficients.len() - 1]; + for (i, a) in self.coefficients.iter().enumerate() { + for (j, b) in other.coefficients.iter().enumerate() { + result[i + j] = result[i + j].clone() + a.clone() * b.clone(); + } + } + Polynomial::new(result) + } +} + +impl Mul for Polynomial { + type Output = Self; + + fn mul(self, other: T) -> Self { + Self::new(self.coefficients.into_iter().map(|x| x * other.clone()).collect()) + } +} + +impl Mul for &Polynomial { + type Output = Polynomial; + + fn mul(self, other: T) -> Polynomial { + Polynomial::new(self.coefficients.iter().cloned().map(|x| x * other.clone()).collect()) + } +} + +impl PartialEq> for Polynomial { + fn eq(&self, other: &Polynomial) -> bool { + if self.coefficients.len() != other.coefficients.len() { + let (shorter, longer) = if self.coefficients.len() < other.coefficients.len() { + (self, other) + } else { + (other, self) + }; + for i in 0..longer.coefficients.len() { + if (i < shorter.coefficients.len() + && shorter.coefficients[i] != longer.coefficients[i]) + || (i >= shorter.coefficients.len() && longer.coefficients[i] != T::zero()) + { + return false; + } + } + return true; + } + self.coefficients == other.coefficients + } +} + +impl Polynomial { + /// Converts the polynomial to a field polynomial. + #[must_use] + pub fn as_field(self) -> Polynomial { + Polynomial { + coefficients: self.coefficients.iter().map(|x| F::from_canonical_u8(*x)).collect(), + } + } +} + +impl<'a, Var: Into + Clone, Expr: Clone> From> for Polynomial { + fn from(value: Iter<'a, Var>) -> Self { + Polynomial::from_coefficients(&value.map(|x| (*x).clone().into()).collect::>()) + } +} diff --git a/core/src/air/public_values.rs b/crates/stark/src/air/public_values.rs similarity index 91% rename from core/src/air/public_values.rs rename to crates/stark/src/air/public_values.rs index 85fc554e1c..dd3965001d 100644 --- a/core/src/air/public_values.rs +++ b/crates/stark/src/air/public_values.rs @@ -1,14 +1,11 @@ -use core::fmt::Debug; -use core::mem::size_of; -use std::borrow::Borrow; -use std::borrow::BorrowMut; +use core::{fmt::Debug, mem::size_of}; +use std::borrow::{Borrow, BorrowMut}; use itertools::Itertools; use p3_field::{AbstractField, PrimeField32}; use serde::{Deserialize, Serialize}; -use super::Word; -use crate::stark::PROOF_MAX_NUM_PVS; +use crate::{Word, PROOF_MAX_NUM_PVS}; /// The number of non padded elements in the SP1 proofs public values vec. pub const SP1_PROOF_NUM_PV_ELTS: usize = size_of::, u8>>(); @@ -16,9 +13,10 @@ pub const SP1_PROOF_NUM_PV_ELTS: usize = size_of::, u8>>() /// The number of 32 bit words in the SP1 proof's commited value digest. pub const PV_DIGEST_NUM_WORDS: usize = 8; +/// The number of field elements in the poseidon2 digest. pub const POSEIDON_NUM_WORDS: usize = 8; -/// The PublicValues struct is used to store all of a shard proof's public values. +/// Stores all of a shard proof's public values. #[derive(Serialize, Deserialize, Clone, Copy, Default, Debug)] #[repr(C)] pub struct PublicValues { @@ -59,8 +57,9 @@ pub struct PublicValues { } impl PublicValues { - /// Convert the public values into a vector of field elements. This function will pad the vector - /// to the maximum number of public values. + /// Convert the public values into a vector of field elements. This function will pad the + /// vector to the maximum number of public values. + #[must_use] pub fn to_vec(&self) -> Vec { let mut ret = vec![F::zero(); PROOF_MAX_NUM_PVS]; @@ -70,6 +69,8 @@ impl PublicValues { ret } + /// Resets the public values to zero. + #[must_use] pub fn reset(&self) -> Self { let mut copy = *self; copy.shard = 0; @@ -170,12 +171,9 @@ impl From> for PublicValues, F> mod tests { use crate::air::public_values; - /// Check that the PI_DIGEST_NUM_WORDS number match the zkVM crate's. + /// Check that the [`PI_DIGEST_NUM_WORDS`] number match the zkVM crate's. #[test] fn test_public_values_digest_num_words_consistency_zkvm() { - assert_eq!( - public_values::PV_DIGEST_NUM_WORDS, - sp1_zkvm::PV_DIGEST_NUM_WORDS - ); + assert_eq!(public_values::PV_DIGEST_NUM_WORDS, sp1_zkvm::PV_DIGEST_NUM_WORDS); } } diff --git a/core/src/air/sub_builder.rs b/crates/stark/src/air/sub_builder.rs similarity index 83% rename from core/src/air/sub_builder.rs rename to crates/stark/src/air/sub_builder.rs index cd1f6be8a8..82b154cea5 100644 --- a/core/src/air/sub_builder.rs +++ b/crates/stark/src/air/sub_builder.rs @@ -1,5 +1,7 @@ -use std::iter::{Skip, Take}; -use std::ops::{Deref, Range}; +use std::{ + iter::{Skip, Take}, + ops::{Deref, Range}, +}; use p3_air::{AirBuilder, BaseAir}; use p3_matrix::Matrix; @@ -12,12 +14,10 @@ pub struct SubMatrixRowSlices, T: Send + Sync> { } impl, T: Send + Sync> SubMatrixRowSlices { + /// Creates a new [`SubMatrixRowSlices`]. + #[must_use] pub const fn new(inner: M, column_range: Range) -> Self { - Self { - inner, - column_range, - _phantom: std::marker::PhantomData, - } + Self { inner, column_range, _phantom: std::marker::PhantomData } } } @@ -27,10 +27,7 @@ impl, T: Send + Sync> Matrix for SubMatrixRowSlices { #[inline] fn row(&self, r: usize) -> Self::Row<'_> { - self.inner - .row(r) - .take(self.column_range.end) - .skip(self.column_range.start) + self.inner.row(r).take(self.column_range.end).skip(self.column_range.start) } #[inline] @@ -51,7 +48,7 @@ impl, T: Send + Sync> Matrix for SubMatrixRowSlices { /// A builder used to eval a sub-air. This will handle enforcing constraints for a subset of a /// trace matrix. E.g. if a particular air needs to be enforced for a subset of the columns of -/// the trace, then the SubAirBuilder can be used. +/// the trace, then the [`SubAirBuilder`] can be used. pub struct SubAirBuilder<'a, AB: AirBuilder, SubAir: BaseAir, T> { inner: &'a mut AB, column_range: Range, @@ -59,12 +56,10 @@ pub struct SubAirBuilder<'a, AB: AirBuilder, SubAir: BaseAir, T> { } impl<'a, AB: AirBuilder, SubAir: BaseAir, T> SubAirBuilder<'a, AB, SubAir, T> { + /// Creates a new [`SubAirBuilder`]. + #[must_use] pub fn new(inner: &'a mut AB, column_range: Range) -> Self { - Self { - inner, - column_range, - _phantom: std::marker::PhantomData, - } + Self { inner, column_range, _phantom: std::marker::PhantomData } } } diff --git a/crates/stark/src/bb31_poseidon2.rs b/crates/stark/src/bb31_poseidon2.rs new file mode 100644 index 0000000000..2c4dd2f7a4 --- /dev/null +++ b/crates/stark/src/bb31_poseidon2.rs @@ -0,0 +1,314 @@ +#![allow(missing_docs)] + +use crate::StarkGenericConfig; +use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; +use p3_challenger::DuplexChallenger; +use p3_commit::ExtensionMmcs; +use p3_dft::Radix2DitParallel; +use p3_field::{extension::BinomialExtensionField, Field}; +use p3_fri::{ + BatchOpening, CommitPhaseProofStep, FriConfig, FriProof, QueryProof, TwoAdicFriPcs, + TwoAdicFriPcsProof, +}; +use p3_merkle_tree::FieldMerkleTreeMmcs; +use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +use p3_symmetric::{Hash, PaddingFreeSponge, TruncatedPermutation}; +use serde::{Deserialize, Serialize}; +use sp1_primitives::poseidon2_init; + +pub const DIGEST_SIZE: usize = 8; + +/// A configuration for inner recursion. +pub type InnerVal = BabyBear; +pub type InnerChallenge = BinomialExtensionField; +pub type InnerPerm = + Poseidon2; +pub type InnerHash = PaddingFreeSponge; +pub type InnerDigestHash = Hash; +pub type InnerDigest = [InnerVal; DIGEST_SIZE]; +pub type InnerCompress = TruncatedPermutation; +pub type InnerValMmcs = FieldMerkleTreeMmcs< + ::Packing, + ::Packing, + InnerHash, + InnerCompress, + 8, +>; +pub type InnerChallengeMmcs = ExtensionMmcs; +pub type InnerChallenger = DuplexChallenger; +pub type InnerDft = Radix2DitParallel; +pub type InnerPcs = TwoAdicFriPcs; +pub type InnerQueryProof = QueryProof; +pub type InnerCommitPhaseStep = CommitPhaseProofStep; +pub type InnerFriProof = FriProof; +pub type InnerBatchOpening = BatchOpening; +pub type InnerPcsProof = + TwoAdicFriPcsProof; + +/// The permutation for inner recursion. +#[must_use] +pub fn inner_perm() -> InnerPerm { + poseidon2_init() +} + +/// The FRI config for sp1 proofs. +#[must_use] +pub fn sp1_fri_config() -> FriConfig { + let perm = inner_perm(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm.clone()); + let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress)); + let num_queries = match std::env::var("FRI_QUERIES") { + Ok(value) => value.parse().unwrap(), + Err(_) => 100, + }; + FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } +} + +/// The FRI config for inner recursion. +#[must_use] +pub fn inner_fri_config() -> FriConfig { + let perm = inner_perm(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm.clone()); + let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress)); + let num_queries = match std::env::var("FRI_QUERIES") { + Ok(value) => value.parse().unwrap(), + Err(_) => 100, + }; + FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } +} + +/// The recursion config used for recursive reduce circuit. +#[derive(Deserialize)] +#[serde(from = "std::marker::PhantomData")] +pub struct BabyBearPoseidon2Inner { + pub perm: InnerPerm, + pub pcs: InnerPcs, +} + +impl Clone for BabyBearPoseidon2Inner { + fn clone(&self) -> Self { + Self::new() + } +} + +impl Serialize for BabyBearPoseidon2Inner { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + std::marker::PhantomData::.serialize(serializer) + } +} + +impl From> for BabyBearPoseidon2Inner { + fn from(_: std::marker::PhantomData) -> Self { + Self::new() + } +} + +impl BabyBearPoseidon2Inner { + #[must_use] + pub fn new() -> Self { + let perm = inner_perm(); + let hash = InnerHash::new(perm.clone()); + let compress = InnerCompress::new(perm.clone()); + let val_mmcs = InnerValMmcs::new(hash, compress); + let dft = InnerDft {}; + let fri_config = inner_fri_config(); + let pcs = InnerPcs::new(27, dft, val_mmcs, fri_config); + Self { perm, pcs } + } +} + +impl Default for BabyBearPoseidon2Inner { + fn default() -> Self { + Self::new() + } +} + +impl StarkGenericConfig for BabyBearPoseidon2Inner { + type Val = InnerVal; + type Domain = >::Domain; + type Pcs = InnerPcs; + type Challenge = InnerChallenge; + type Challenger = InnerChallenger; + + fn pcs(&self) -> &Self::Pcs { + &self.pcs + } + + fn challenger(&self) -> Self::Challenger { + InnerChallenger::new(self.perm.clone()) + } +} + +pub mod baby_bear_poseidon2 { + + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_challenger::DuplexChallenger; + use p3_commit::ExtensionMmcs; + use p3_dft::Radix2DitParallel; + use p3_field::{extension::BinomialExtensionField, Field}; + use p3_fri::{FriConfig, TwoAdicFriPcs}; + use p3_merkle_tree::FieldMerkleTreeMmcs; + use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; + use serde::{Deserialize, Serialize}; + use sp1_primitives::RC_16_30; + + use crate::StarkGenericConfig; + + pub type Val = BabyBear; + pub type Challenge = BinomialExtensionField; + + pub type Perm = Poseidon2; + pub type MyHash = PaddingFreeSponge; + pub type MyCompress = TruncatedPermutation; + pub type ValMmcs = FieldMerkleTreeMmcs< + ::Packing, + ::Packing, + MyHash, + MyCompress, + 8, + >; + pub type ChallengeMmcs = ExtensionMmcs; + pub type Dft = Radix2DitParallel; + pub type Challenger = DuplexChallenger; + type Pcs = TwoAdicFriPcs; + + #[must_use] + pub fn my_perm() -> Perm { + const ROUNDS_F: usize = 8; + const ROUNDS_P: usize = 13; + let mut round_constants = RC_16_30.to_vec(); + let internal_start = ROUNDS_F / 2; + let internal_end = (ROUNDS_F / 2) + ROUNDS_P; + let internal_round_constants = round_constants + .drain(internal_start..internal_end) + .map(|vec| vec[0]) + .collect::>(); + let external_round_constants = round_constants; + Perm::new( + ROUNDS_F, + external_round_constants, + Poseidon2ExternalMatrixGeneral, + ROUNDS_P, + internal_round_constants, + DiffusionMatrixBabyBear, + ) + } + + #[must_use] + pub fn default_fri_config() -> FriConfig { + let perm = my_perm(); + let hash = MyHash::new(perm.clone()); + let compress = MyCompress::new(perm.clone()); + let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress)); + let num_queries = match std::env::var("FRI_QUERIES") { + Ok(value) => value.parse().unwrap(), + Err(_) => 100, + }; + FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } + } + + #[must_use] + pub fn compressed_fri_config() -> FriConfig { + let perm = my_perm(); + let hash = MyHash::new(perm.clone()); + let compress = MyCompress::new(perm.clone()); + let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress)); + let num_queries = match std::env::var("FRI_QUERIES") { + Ok(value) => value.parse().unwrap(), + Err(_) => 33, + }; + FriConfig { log_blowup: 3, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs } + } + + enum BabyBearPoseidon2Type { + Default, + Compressed, + } + + #[derive(Deserialize)] + #[serde(from = "std::marker::PhantomData")] + pub struct BabyBearPoseidon2 { + pub perm: Perm, + pcs: Pcs, + config_type: BabyBearPoseidon2Type, + } + + impl BabyBearPoseidon2 { + #[must_use] + pub fn new() -> Self { + let perm = my_perm(); + let hash = MyHash::new(perm.clone()); + let compress = MyCompress::new(perm.clone()); + let val_mmcs = ValMmcs::new(hash, compress); + let dft = Dft {}; + let fri_config = default_fri_config(); + let pcs = Pcs::new(27, dft, val_mmcs, fri_config); + Self { pcs, perm, config_type: BabyBearPoseidon2Type::Default } + } + + #[must_use] + pub fn compressed() -> Self { + let perm = my_perm(); + let hash = MyHash::new(perm.clone()); + let compress = MyCompress::new(perm.clone()); + let val_mmcs = ValMmcs::new(hash, compress); + let dft = Dft {}; + let fri_config = compressed_fri_config(); + let pcs = Pcs::new(27, dft, val_mmcs, fri_config); + Self { pcs, perm, config_type: BabyBearPoseidon2Type::Compressed } + } + } + + impl Clone for BabyBearPoseidon2 { + fn clone(&self) -> Self { + match self.config_type { + BabyBearPoseidon2Type::Default => Self::new(), + BabyBearPoseidon2Type::Compressed => Self::compressed(), + } + } + } + + impl Default for BabyBearPoseidon2 { + fn default() -> Self { + Self::new() + } + } + + /// Implement serialization manually instead of using serde to avoid cloing the config. + impl Serialize for BabyBearPoseidon2 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + std::marker::PhantomData::.serialize(serializer) + } + } + + impl From> for BabyBearPoseidon2 { + fn from(_: std::marker::PhantomData) -> Self { + Self::new() + } + } + + impl StarkGenericConfig for BabyBearPoseidon2 { + type Val = BabyBear; + type Domain = >::Domain; + type Pcs = Pcs; + type Challenge = Challenge; + type Challenger = Challenger; + + fn pcs(&self) -> &Self::Pcs { + &self.pcs + } + + fn challenger(&self) -> Self::Challenger { + Challenger::new(self.perm.clone()) + } + } +} diff --git a/core/src/stark/chip.rs b/crates/stark/src/chip.rs similarity index 85% rename from core/src/stark/chip.rs rename to crates/stark/src/chip.rs index 534c444735..5d58986c4a 100644 --- a/core/src/stark/chip.rs +++ b/crates/stark/src/chip.rs @@ -55,6 +55,7 @@ impl> Chip { impl Chip where F: Field, + A: BaseAir, { /// Records the interactions and constraint degree from the air and crates a new chip. pub fn new(air: A) -> Self @@ -65,14 +66,8 @@ where air.eval(&mut builder); let (sends, receives) = builder.interactions(); - let nb_byte_sends = sends - .iter() - .filter(|s| s.kind == InteractionKind::Byte) - .count(); - let nb_byte_receives = receives - .iter() - .filter(|r| r.kind == InteractionKind::Byte) - .count(); + let nb_byte_sends = sends.iter().filter(|s| s.kind == InteractionKind::Byte).count(); + let nb_byte_receives = receives.iter().filter(|r| r.kind == InteractionKind::Byte).count(); tracing::debug!( "chip {} has {} byte interactions", air.name(), @@ -87,29 +82,28 @@ where } let log_quotient_degree = log2_ceil_usize(max_constraint_degree - 1); - Self { - air, - sends, - receives, - log_quotient_degree, - } + Self { air, sends, receives, log_quotient_degree } } + /// Returns the number of interactions in the chip. #[inline] pub fn num_interactions(&self) -> usize { self.sends.len() + self.receives.len() } + /// Returns the number of sends of the given kind. #[inline] pub fn num_sends_by_kind(&self, kind: InteractionKind) -> usize { self.sends.iter().filter(|i| i.kind == kind).count() } + /// Returns the number of receives of the given kind. #[inline] pub fn num_receives_by_kind(&self, kind: InteractionKind) -> usize { self.receives.iter().filter(|i| i.kind == kind).count() } + /// Generates a permutation trace for the given matrix. pub fn generate_permutation_trace>( &self, preprocessed: Option<&RowMajorMatrix>, @@ -130,19 +124,25 @@ where ) } + /// Returns the width of the permutation trace. #[inline] pub fn permutation_width(&self) -> usize { - permutation_trace_width( - self.sends().len() + self.receives().len(), - self.logup_batch_size(), - ) + permutation_trace_width(self.sends().len() + self.receives().len(), self.logup_batch_size()) + } + + /// Returns the cost of a row in the chip. + #[inline] + pub fn cost(&self) -> u64 { + (self.width() + 4 * self.permutation_width()) as u64 } + /// Returns the width of the quotient polynomial. #[inline] pub const fn quotient_width(&self) -> usize { 1 << self.log_quotient_degree } + /// Returns the log2 of the batch size. #[inline] pub const fn logup_batch_size(&self) -> usize { 1 << self.log_quotient_degree @@ -189,7 +189,7 @@ where } fn generate_dependencies(&self, input: &A::Record, output: &mut A::Record) { - self.air.generate_dependencies(input, output) + self.air.generate_dependencies(input, output); } fn included(&self, shard: &Self::Record) -> bool { diff --git a/core/src/stark/config.rs b/crates/stark/src/config.rs similarity index 99% rename from core/src/stark/config.rs rename to crates/stark/src/config.rs index b944fbfe80..59df5f0165 100644 --- a/core/src/stark/config.rs +++ b/crates/stark/src/config.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use p3_challenger::{CanObserve, CanSample, FieldChallenger}; use p3_commit::{Pcs, PolynomialSpace}; use p3_field::{ExtensionField, Field, PrimeField}; diff --git a/core/src/stark/debug.rs b/crates/stark/src/debug.rs similarity index 91% rename from core/src/stark/debug.rs rename to crates/stark/src/debug.rs index 1111627b07..2e1ccd9d3d 100644 --- a/core/src/stark/debug.rs +++ b/crates/stark/src/debug.rs @@ -1,16 +1,19 @@ -use std::borrow::Borrow; -use std::panic::{self, AssertUnwindSafe}; -use std::process::exit; +use std::{ + borrow::Borrow, + panic::{self, AssertUnwindSafe}, + process::exit, +}; use p3_air::{ Air, AirBuilder, AirBuilderWithPublicValues, ExtensionBuilder, PairBuilder, PermutationAirBuilder, }; -use p3_field::{AbstractField, PrimeField32}; -use p3_field::{ExtensionField, Field}; -use p3_matrix::dense::RowMajorMatrixView; -use p3_matrix::stack::VerticalPair; -use p3_matrix::{dense::RowMajorMatrix, Matrix}; +use p3_field::{AbstractField, ExtensionField, Field, PrimeField32}; +use p3_matrix::{ + dense::{RowMajorMatrix, RowMajorMatrixView}, + stack::VerticalPair, + Matrix, +}; use super::{MachineChip, StarkGenericConfig, Val}; use crate::air::{EmptyMessageBuilder, MachineAir, MultiTableAirBuilder}; @@ -18,6 +21,7 @@ use crate::air::{EmptyMessageBuilder, MachineAir, MultiTableAirBuilder}; /// Checks that the constraints of the given AIR are satisfied, including the permutation trace. /// /// Note that this does not actually verify the proof. +#[allow(clippy::needless_pass_by_value)] pub fn debug_constraints( chip: &MachineChip, preprocessed: Option<&RowMajorMatrix>>, @@ -65,7 +69,7 @@ pub fn debug_constraints( let perm_next = perm.row_slice(i_next); let perm_next = &(*perm_next); - let public_values = public_values.to_vec(); + let public_values = public_values.clone(); let mut builder = DebugConstraintBuilder { preprocessed: VerticalPair::new( RowMajorMatrixView::new_row(&preprocessed_local), @@ -97,8 +101,8 @@ pub fn debug_constraints( chip.eval(&mut builder); })); if result.is_err() { - eprintln!("local: {:?}", main_local); - eprintln!("next: {:?}", main_next); + eprintln!("local: {main_local:?}"); + eprintln!("next: {main_next:?}"); eprintln!("failed at row {} of chip {}", i, chip.name()); exit(1); } @@ -117,10 +121,7 @@ fn catch_unwind_silent R + panic::UnwindSafe, R>(f: F) -> std::th /// /// Note that this does not actually verify the proof. pub fn debug_cumulative_sums>(perms: &[RowMajorMatrix]) { - let sum: EF = perms - .iter() - .map(|perm| *perm.row_slice(perm.height() - 1).last().unwrap()) - .sum(); + let sum: EF = perms.iter().map(|perm| *perm.row_slice(perm.height() - 1).last().unwrap()).sum(); assert_eq!(sum, EF::zero()); } @@ -187,11 +188,12 @@ where F: Field, EF: ExtensionField, { + #[allow(clippy::unused_self)] #[inline] fn debug_constraint(&self, x: F, y: F) { if x != y { let backtrace = std::backtrace::Backtrace::force_capture(); - eprintln!("constraint failed: {:?} != {:?}\n{}", x, y, backtrace); + eprintln!("constraint failed: {x:?} != {y:?}\n{backtrace}"); panic!(); } } @@ -244,7 +246,7 @@ where let x = x.into(); if x != F::zero() && x != F::one() { let backtrace = std::backtrace::Backtrace::force_capture(); - eprintln!("constraint failed: {:?} is not a bool\n{}", x, backtrace); + eprintln!("constraint failed: {x:?} is not a bool\n{backtrace}"); panic!(); } } diff --git a/core/src/stark/folder.rs b/crates/stark/src/folder.rs similarity index 92% rename from core/src/stark/folder.rs rename to crates/stark/src/folder.rs index ad902a5af9..a99e06c31b 100644 --- a/core/src/stark/folder.rs +++ b/crates/stark/src/folder.rs @@ -4,8 +4,7 @@ use std::{ }; use p3_field::{AbstractField, ExtensionField, Field}; -use p3_matrix::dense::RowMajorMatrixView; -use p3_matrix::stack::VerticalPair; +use p3_matrix::{dense::RowMajorMatrixView, stack::VerticalPair}; use super::{Challenge, PackedChallenge, PackedVal, StarkGenericConfig, Val}; use crate::air::{EmptyMessageBuilder, MultiTableAirBuilder}; @@ -15,21 +14,32 @@ use p3_air::{ /// A folder for prover constraints. pub struct ProverConstraintFolder<'a, SC: StarkGenericConfig> { + /// The preprocessed trace. pub preprocessed: VerticalPair>, RowMajorMatrixView<'a, PackedVal>>, + /// The main trace. pub main: VerticalPair>, RowMajorMatrixView<'a, PackedVal>>, + /// The permutation trace. pub perm: VerticalPair< RowMajorMatrixView<'a, PackedChallenge>, RowMajorMatrixView<'a, PackedChallenge>, >, + /// The challenges for the permutation. pub perm_challenges: &'a [PackedChallenge], + /// The cumulative sum of the permutation. pub cumulative_sum: SC::Challenge, + /// The selector for the first row. pub is_first_row: PackedVal, + /// The selector for the last row. pub is_last_row: PackedVal, + /// The selector for the transition. pub is_transition: PackedVal, + /// The constraint folding challenge. pub alpha: SC::Challenge, + /// The accumulator for the constraint folding. pub accumulator: PackedChallenge, + /// The public values. pub public_values: &'a [Val], } @@ -125,6 +135,7 @@ impl<'a, SC: StarkGenericConfig> AirBuilderWithPublicValues for ProverConstraint } } +/// A folder for verifier constraints. pub type VerifierConstraintFolder<'a, SC> = GenericVerifierConstraintFolder< 'a, Val, @@ -136,17 +147,29 @@ pub type VerifierConstraintFolder<'a, SC> = GenericVerifierConstraintFolder< /// A folder for verifier constraints. pub struct GenericVerifierConstraintFolder<'a, F, EF, PubVar, Var, Expr> { + /// The preprocessed trace. pub preprocessed: VerticalPair, RowMajorMatrixView<'a, Var>>, + /// The main trace. pub main: VerticalPair, RowMajorMatrixView<'a, Var>>, + /// The permutation trace. pub perm: VerticalPair, RowMajorMatrixView<'a, Var>>, + /// The challenges for the permutation. pub perm_challenges: &'a [Var], + /// The cumulative sum of the permutation. pub cumulative_sum: Var, + /// The selector for the first row. pub is_first_row: Var, + /// The selector for the last row. pub is_last_row: Var, + /// The selector for the transition. pub is_transition: Var, + /// The constraint folding challenge. pub alpha: Var, + /// The accumulator for the constraint folding. pub accumulator: Expr, + /// The public values. pub public_values: &'a [PubVar], + /// The marker type. pub _marker: PhantomData<(F, EF)>, } @@ -248,7 +271,7 @@ where where I: Into, { - self.assert_zero(x) + self.assert_zero(x); } } diff --git a/crates/stark/src/lib.rs b/crates/stark/src/lib.rs new file mode 100644 index 0000000000..924dcb3356 --- /dev/null +++ b/crates/stark/src/lib.rs @@ -0,0 +1,55 @@ +//! STARK-based primitives for proof generation and verification over AIRs. + +#![warn(clippy::pedantic)] +#![allow(clippy::similar_names)] +#![allow(clippy::cast_possible_wrap)] +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_sign_loss)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::needless_range_loop)] +#![allow(clippy::cast_lossless)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::should_panic_without_expect)] +#![allow(clippy::field_reassign_with_default)] +#![allow(clippy::manual_assert)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::explicit_iter_loop)] +#![allow(clippy::if_not_else)] +#![warn(missing_docs)] + +pub mod air; +mod bb31_poseidon2; +mod chip; +mod config; +mod debug; +mod folder; +mod lookup; +mod machine; +mod opts; +mod permutation; +mod prover; +mod quotient; +mod record; +mod types; +mod util; +mod verifier; +mod word; + +pub use bb31_poseidon2::*; +pub use chip::*; +pub use config::*; +pub use debug::*; +pub use folder::*; +pub use lookup::*; +pub use machine::*; +pub use opts::*; +pub use permutation::*; +pub use prover::*; +pub use quotient::*; +pub use record::*; +pub use types::*; +pub use verifier::*; +pub use word::*; diff --git a/core/src/lookup/builder.rs b/crates/stark/src/lookup/builder.rs similarity index 85% rename from core/src/lookup/builder.rs rename to crates/stark/src/lookup/builder.rs index a342425d43..df0fa8a75b 100644 --- a/core/src/lookup/builder.rs +++ b/crates/stark/src/lookup/builder.rs @@ -5,7 +5,7 @@ use p3_uni_stark::{Entry, SymbolicExpression, SymbolicVariable}; use crate::{ air::{AirInteraction, MessageBuilder}, - stark::PROOF_MAX_NUM_PVS, + PROOF_MAX_NUM_PVS, }; use super::Interaction; @@ -20,7 +20,8 @@ pub struct InteractionBuilder { } impl InteractionBuilder { - /// Creates a new `InteractionBuilder` with the given width. + /// Creates a new [`InteractionBuilder`] with the given width. + #[must_use] pub fn new(preprocessed_width: usize, main_width: usize) -> Self { let preprocessed_width = preprocessed_width.max(1); let prep_values = [0, 1] @@ -50,6 +51,7 @@ impl InteractionBuilder { } /// Returns the sends and receives. + #[must_use] pub fn interactions(self) -> (Vec>, Vec>) { (self.sends, self.receives) } @@ -92,29 +94,21 @@ impl PairBuilder for InteractionBuilder { impl MessageBuilder>> for InteractionBuilder { fn send(&mut self, message: AirInteraction>) { - let values = message - .values - .into_iter() - .map(|v| symbolic_to_virtual_pair(&v)) - .collect::>(); + let values = + message.values.into_iter().map(|v| symbolic_to_virtual_pair(&v)).collect::>(); let multiplicity = symbolic_to_virtual_pair(&message.multiplicity); - self.sends - .push(Interaction::new(values, multiplicity, message.kind)); + self.sends.push(Interaction::new(values, multiplicity, message.kind)); } fn receive(&mut self, message: AirInteraction>) { - let values = message - .values - .into_iter() - .map(|v| symbolic_to_virtual_pair(&v)) - .collect::>(); + let values = + message.values.into_iter().map(|v| symbolic_to_virtual_pair(&v)).collect::>(); let multiplicity = symbolic_to_virtual_pair(&message.multiplicity); - self.receives - .push(Interaction::new(values, multiplicity, message.kind)); + self.receives.push(Interaction::new(values, multiplicity, message.kind)); } } @@ -148,10 +142,7 @@ fn eval_symbolic_to_virtual_pair( (vec![(PairCol::Preprocessed(v.index), F::one())], F::zero()) } Entry::Main { offset: 0 } => (vec![(PairCol::Main(v.index), F::one())], F::zero()), - _ => panic!( - "Not an affine expression in current row elements {:?}", - v.entry - ), + _ => panic!("not an affine expression in current row elements {:?}", v.entry), }, SymbolicExpression::Add { x, y, .. } => { let (v_l, c_l) = eval_symbolic_to_virtual_pair(x); @@ -183,14 +174,13 @@ fn eval_symbolic_to_virtual_pair( (v, c_l * c_r) } SymbolicExpression::IsFirstRow => { - panic!("Not an affine expression in current row elements") + panic!("not an affine expression in current row elements for first row") } - SymbolicExpression::IsLastRow => { - panic!("Not an affine expression in current row elements") + panic!("not an affine expression in current row elements for last row") } SymbolicExpression::IsTransition => { - panic!("Not an affine expression in current row elements") + panic!("not an affine expression in current row elements for transition row") } } } @@ -218,8 +208,8 @@ mod tests { let z = x + y; let (column_weights, constant) = super::eval_symbolic_to_virtual_pair(&z); - println!("column_weights: {:?}", column_weights); - println!("constant: {:?}", constant); + println!("column_weights: {column_weights:?}"); + println!("constant: {constant:?}"); let column_weights = column_weights.into_iter().collect::>(); @@ -227,7 +217,7 @@ mod tests { let expr: F = z.apply(&[], &[F::one(), F::one()]); - println!("expr: {}", expr); + println!("expr: {expr}"); } pub struct LookupTestAir; @@ -261,11 +251,7 @@ mod tests { InteractionKind::Alu, )); - builder.receive(AirInteraction::new( - vec![x.into()], - y.into(), - InteractionKind::Byte, - )); + builder.receive(AirInteraction::new(vec![x.into()], y.into(), InteractionKind::Byte)); } } @@ -287,7 +273,7 @@ mod tests { &[], main.row_mut(0), ); - print!("{:?}, ", expr); + print!("{expr:?}, "); } let multiplicity = interaction @@ -297,7 +283,7 @@ mod tests { main.row_mut(0), ); - println!(", multiplicity: {:?}", multiplicity); + println!(", multiplicity: {multiplicity:?}"); } for interaction in sends { @@ -307,7 +293,7 @@ mod tests { &[], main.row_mut(0), ); - print!("{:?}, ", expr); + print!("{expr:?}, "); } let multiplicity = interaction @@ -317,7 +303,7 @@ mod tests { main.row_mut(0), ); - println!(", multiplicity: {:?}", multiplicity); + println!(", multiplicity: {multiplicity:?}"); } } } diff --git a/core/src/lookup/debug.rs b/crates/stark/src/lookup/debug.rs similarity index 67% rename from core/src/lookup/debug.rs rename to crates/stark/src/lookup/debug.rs index 546ec25147..b555cb0471 100644 --- a/core/src/lookup/debug.rs +++ b/crates/stark/src/lookup/debug.rs @@ -1,24 +1,32 @@ use std::collections::BTreeMap; use p3_baby_bear::BabyBear; -use p3_field::{AbstractField, PrimeField32}; -use p3_field::{Field, PrimeField64}; +use p3_field::{AbstractField, Field, PrimeField32, PrimeField64}; use p3_matrix::Matrix; use super::InteractionKind; -use crate::air::MachineAir; -use crate::stark::{MachineChip, StarkGenericConfig, StarkMachine, StarkProvingKey, Val}; +use crate::{air::MachineAir, MachineChip, StarkGenericConfig, StarkMachine, StarkProvingKey, Val}; +/// The data for an interaction. #[derive(Debug)] pub struct InteractionData { + /// The chip name. pub chip_name: String, + /// The kind of interaction. pub kind: InteractionKind, + /// The row of the interaction. pub row: usize, + /// The interaction number. pub interaction_number: usize, + /// Whether the interaction is a send. pub is_send: bool, + /// The multiplicity of the interaction. pub multiplicity: F, } +/// Converts a vector of field elements to a string. +#[allow(clippy::needless_pass_by_value)] +#[must_use] pub fn vec_to_string(vec: Vec) -> String { let mut result = String::from("("); for (i, value) in vec.iter().enumerate() { @@ -45,35 +53,28 @@ fn field_to_int(x: F) -> i32 { } } +/// Debugs the interactions of a chip. +#[allow(clippy::type_complexity)] +#[allow(clippy::needless_pass_by_value)] pub fn debug_interactions>>( chip: &MachineChip, pkey: &StarkProvingKey, record: &A::Record, interaction_kinds: Vec, -) -> ( - BTreeMap>>>, - BTreeMap>, -) { +) -> (BTreeMap>>>, BTreeMap>) { let mut key_to_vec_data = BTreeMap::new(); let mut key_to_count = BTreeMap::new(); let trace = chip.generate_trace(record, &mut A::Record::default()); let mut pre_traces = pkey.traces.clone(); - let mut preprocessed_trace = pkey - .chip_ordering - .get(&chip.name()) - .map(|&index| pre_traces.get_mut(index).unwrap()); + let mut preprocessed_trace = + pkey.chip_ordering.get(&chip.name()).map(|&index| pre_traces.get_mut(index).unwrap()); let mut main = trace.clone(); let height = trace.clone().height(); let nb_send_interactions = chip.sends().len(); for row in 0..height { - for (m, interaction) in chip - .sends() - .iter() - .chain(chip.receives().iter()) - .enumerate() - { + for (m, interaction) in chip.sends().iter().chain(chip.receives().iter()).enumerate() { if !interaction_kinds.contains(&interaction.kind) { continue; } @@ -84,9 +85,8 @@ pub fn debug_interactions>>( .or_else(|| Some(&mut empty)) .unwrap(); let is_send = m < nb_send_interactions; - let multiplicity_eval: Val = interaction - .multiplicity - .apply(preprocessed_row, main.row_mut(row)); + let multiplicity_eval: Val = + interaction.multiplicity.apply(preprocessed_row, main.row_mut(row)); if !multiplicity_eval.is_zero() { let mut values = vec![]; @@ -94,22 +94,15 @@ pub fn debug_interactions>>( let expr: Val = value.apply(preprocessed_row, main.row_mut(row)); values.push(expr); } - let key = format!( - "{} {}", - &interaction.kind.to_string(), - vec_to_string(values) - ); - key_to_vec_data - .entry(key.clone()) - .or_insert_with(Vec::new) - .push(InteractionData { - chip_name: chip.name(), - kind: interaction.kind, - row, - interaction_number: m, - is_send, - multiplicity: multiplicity_eval, - }); + let key = format!("{} {}", &interaction.kind.to_string(), vec_to_string(values)); + key_to_vec_data.entry(key.clone()).or_insert_with(Vec::new).push(InteractionData { + chip_name: chip.name(), + kind: interaction.kind, + row, + interaction_number: m, + is_send, + multiplicity: multiplicity_eval, + }); let current = key_to_count.entry(key.clone()).or_insert(Val::::zero()); if is_send { *current += multiplicity_eval; @@ -125,6 +118,7 @@ pub fn debug_interactions>>( /// Calculate the number of times we send and receive each event of the given interaction type, /// and print out the ones for which the set of sends and receives don't match. +#[allow(clippy::needless_pass_by_value)] pub fn debug_interactions_with_all_chips( machine: &StarkMachine, pkey: &StarkProvingKey, @@ -147,9 +141,8 @@ where debug_interactions::(chip, pkey, shard, interaction_kinds.clone()); total_events += count.len(); for (key, value) in count.iter() { - let entry = final_map - .entry(key.clone()) - .or_insert((SC::Val::zero(), BTreeMap::new())); + let entry = + final_map.entry(key.clone()).or_insert((SC::Val::zero(), BTreeMap::new())); entry.0 += *value; total += *value; *entry.1.entry(chip.name()).or_insert(SC::Val::zero()) += *value; @@ -203,37 +196,3 @@ where !any_nonzero } - -#[cfg(test)] -mod test { - - use crate::{ - lookup::InteractionKind, - runtime::{Program, Runtime}, - stark::RiscvAir, - utils::{setup_logger, tests::UINT256_MUL_ELF, BabyBearPoseidon2, SP1CoreOpts}, - }; - - use super::debug_interactions_with_all_chips; - - #[test] - fn test_debug_interactions() { - setup_logger(); - let program = Program::from(UINT256_MUL_ELF); - let config = BabyBearPoseidon2::new(); - let machine = RiscvAir::machine(config); - let (pk, _) = machine.setup(&program); - let mut runtime = Runtime::new(program, SP1CoreOpts::default()); - runtime.run().unwrap(); - let opts = SP1CoreOpts::default(); - machine.generate_dependencies(&mut runtime.records, &opts); - - let mut shards = runtime.records; - shards.iter_mut().enumerate().for_each(|(i, shard)| { - shard.public_values.shard = (i + 1) as u32; - }); - let ok = - debug_interactions_with_all_chips(&machine, &pk, &shards, InteractionKind::all_kinds()); - assert!(ok); - } -} diff --git a/core/src/lookup/interaction.rs b/crates/stark/src/lookup/interaction.rs similarity index 88% rename from core/src/lookup/interaction.rs rename to crates/stark/src/lookup/interaction.rs index 1c20938cc4..04538aa179 100644 --- a/core/src/lookup/interaction.rs +++ b/crates/stark/src/lookup/interaction.rs @@ -1,13 +1,15 @@ -use core::fmt::Debug; -use core::fmt::Display; +use core::fmt::{Debug, Display}; use p3_air::VirtualPairCol; use p3_field::Field; /// An interaction for a lookup or a permutation argument. pub struct Interaction { + /// The values of the interaction. pub values: Vec>, + /// The multiplicity of the interaction. pub multiplicity: VirtualPairCol, + /// The kind of interaction. pub kind: InteractionKind, } @@ -40,6 +42,8 @@ pub enum InteractionKind { } impl InteractionKind { + /// Returns all kinds of interactions. + #[must_use] pub fn all_kinds() -> Vec { vec![ InteractionKind::Memory, @@ -61,11 +65,7 @@ impl Interaction { multiplicity: VirtualPairCol, kind: InteractionKind, ) -> Self { - Self { - values, - multiplicity, - kind, - } + Self { values, multiplicity, kind } } /// The index of the argument in the lookup table. @@ -76,9 +76,7 @@ impl Interaction { impl Debug for Interaction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Interaction") - .field("kind", &self.kind) - .finish() + f.debug_struct("Interaction").field("kind", &self.kind).finish_non_exhaustive() } } diff --git a/core/src/lookup/mod.rs b/crates/stark/src/lookup/mod.rs similarity index 100% rename from core/src/lookup/mod.rs rename to crates/stark/src/lookup/mod.rs diff --git a/core/src/stark/machine.rs b/crates/stark/src/machine.rs similarity index 53% rename from core/src/stark/machine.rs rename to crates/stark/src/machine.rs index 0dd3310e14..882bd2a04d 100644 --- a/core/src/stark/machine.rs +++ b/crates/stark/src/machine.rs @@ -1,44 +1,28 @@ use hashbrown::HashMap; use itertools::Itertools; use p3_air::Air; -use p3_challenger::CanObserve; -use p3_challenger::FieldChallenger; +use p3_challenger::{CanObserve, FieldChallenger}; use p3_commit::Pcs; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use p3_field::Field; -use p3_field::PrimeField32; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Dimensions; -use p3_matrix::Matrix; +use p3_field::{AbstractExtensionField, AbstractField, Field, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Dimensions, Matrix}; use p3_maybe_rayon::prelude::*; -use serde::de::DeserializeOwned; -use serde::Deserialize; -use serde::Serialize; -use std::cmp::Reverse; -use std::fmt::Debug; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::{cmp::Reverse, fmt::Debug, time::Instant}; use tracing::instrument; -use super::debug_constraints; -use super::Dom; -use crate::air::MachineAir; -use crate::air::MachineProgram; -use crate::lookup::debug_interactions_with_all_chips; -use crate::lookup::InteractionKind; -use crate::stark::record::MachineRecord; -use crate::stark::DebugConstraintBuilder; -use crate::stark::ShardProof; -use crate::stark::VerifierConstraintFolder; - -use super::Chip; -use super::Com; -use super::MachineProof; -use super::PcsProverData; -use super::StarkGenericConfig; -use super::Val; -use super::VerificationError; -use super::Verifier; +use super::{debug_constraints, Dom}; +use crate::{ + air::{MachineAir, MachineProgram}, + lookup::{debug_interactions_with_all_chips, InteractionKind}, + record::MachineRecord, + DebugConstraintBuilder, ShardProof, VerifierConstraintFolder, +}; +use super::{ + Chip, Com, MachineProof, PcsProverData, StarkGenericConfig, Val, VerificationError, Verifier, +}; + +/// A chip in a machine. pub type MachineChip = Chip, A>; /// A STARK for proving RISC-V execution. @@ -53,44 +37,54 @@ pub struct StarkMachine { } impl StarkMachine { + /// Creates a new [`StarkMachine`]. pub const fn new(config: SC, chips: Vec, A>>, num_pv_elts: usize) -> Self { - Self { - config, - chips, - num_pv_elts, - } + Self { config, chips, num_pv_elts } } } +/// A proving key for a STARK. #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "PcsProverData: Serialize"))] #[serde(bound(deserialize = "PcsProverData: DeserializeOwned"))] pub struct StarkProvingKey { + /// The commitment to the preprocessed traces. pub commit: Com, + /// The start pc of the program. pub pc_start: Val, + /// The preprocessed traces. pub traces: Vec>>, + /// The pcs data for the preprocessed traces. pub data: PcsProverData, + /// The preprocessed chip ordering. pub chip_ordering: HashMap, } impl StarkProvingKey { + /// Observes the values of the proving key into the challenger. pub fn observe_into(&self, challenger: &mut SC::Challenger) { challenger.observe(self.commit.clone()); challenger.observe(self.pc_start); } } +/// A verifying key for a STARK. #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "Dom: Serialize"))] #[serde(bound(deserialize = "Dom: DeserializeOwned"))] pub struct StarkVerifyingKey { + /// The commitment to the preprocessed traces. pub commit: Com, + /// The start pc of the program. pub pc_start: Val, + /// The chip information. pub chip_information: Vec<(String, Dom, Dimensions)>, + /// The chip ordering. pub chip_ordering: HashMap, } impl StarkVerifyingKey { + /// Observes the values of the verifying key into the challenger. pub fn observe_into(&self, challenger: &mut SC::Challenger) { challenger.observe(self.commit.clone()); challenger.observe(self.pc_start); @@ -109,6 +103,7 @@ impl>> StarkMachine { &self.chips } + /// Returns the number of public values elements. pub const fn num_pv_elts(&self) -> usize { self.num_pv_elts } @@ -123,6 +118,7 @@ impl>> StarkMachine { .collect() } + /// Returns an iterator over the chips in the machine that are included in the given shard. pub fn shard_chips<'a, 'b>( &'a self, shard: &'b A::Record, @@ -133,6 +129,7 @@ impl>> StarkMachine { self.chips.iter().filter(|chip| chip.included(shard)) } + /// Returns an iterator over the chips in the machine that are included in the given shard. pub fn shard_chips_ordered<'a, 'b>( &'a self, chip_ordering: &'b HashMap, @@ -146,11 +143,9 @@ impl>> StarkMachine { .sorted_by_key(|chip| chip_ordering.get(&chip.name())) } + /// Returns the indices of the chips in the machine that are included in the given shard. pub fn chips_sorted_indices(&self, proof: &ShardProof) -> Vec> { - self.chips() - .iter() - .map(|chip| proof.chip_ordering.get(&chip.name()).cloned()) - .collect() + self.chips().iter().map(|chip| proof.chip_ordering.get(&chip.name()).copied()).collect() } /// The setup preprocessing phase. @@ -158,31 +153,34 @@ impl>> StarkMachine { /// Given a program, this function generates the proving and verifying keys. The keys correspond /// to the program code and other preprocessed colunms such as lookup tables. #[instrument("setup machine", level = "debug", skip_all)] + #[allow(clippy::map_unwrap_or)] + #[allow(clippy::redundant_closure_for_method_calls)] pub fn setup(&self, program: &A::Program) -> (StarkProvingKey, StarkVerifyingKey) { - let mut named_preprocessed_traces = tracing::debug_span!("generate preprocessed traces") - .in_scope(|| { - self.chips() - .iter() - .map(|chip| { - let prep_trace = chip.generate_preprocessed_trace(program); - // Assert that the chip width data is correct. - let expected_width = prep_trace.as_ref().map(|t| t.width()).unwrap_or(0); - assert_eq!( - expected_width, - chip.preprocessed_width(), - "Incorrect number of preprocessed columns for chip {}", - chip.name() - ); - - (chip.name(), prep_trace) - }) - .filter(|(_, prep_trace)| prep_trace.is_some()) - .map(|(name, prep_trace)| { - let prep_trace = prep_trace.unwrap(); - (name, prep_trace) - }) - .collect::>() - }); + let parent_span = tracing::debug_span!("generate preprocessed traces"); + let mut named_preprocessed_traces = parent_span.in_scope(|| { + self.chips() + .par_iter() + .filter_map(|chip| { + let chip_name = chip.name(); + let begin = Instant::now(); + let prep_trace = chip.generate_preprocessed_trace(program); + tracing::debug!( + parent: &parent_span, + "generated preprocessed trace for chip {} in {:?}", + chip_name, + begin.elapsed() + ); + // Assert that the chip width data is correct. + let expected_width = prep_trace.as_ref().map(|t| t.width()).unwrap_or(0); + assert_eq!( + expected_width, + chip.preprocessed_width(), + "Incorrect number of preprocessed columns for chip {chip_name}" + ); + prep_trace.map(move |t| (chip_name, t)) + }) + .collect::>() + }); // Order the chips and traces by trace size (biggest first), and get the ordering map. named_preprocessed_traces.sort_by_key(|(_, trace)| Reverse(trace.height())); @@ -193,10 +191,7 @@ impl>> StarkMachine { .iter() .map(|(name, trace)| { let domain = pcs.natural_domain_for_degree(trace.height()); - ( - (name.to_owned(), domain, trace.dimensions()), - (domain, trace.to_owned()), - ) + ((name.to_owned(), domain, trace.dimensions()), (domain, trace.to_owned())) }) .unzip(); @@ -212,10 +207,8 @@ impl>> StarkMachine { .collect::>(); // Get the preprocessed traces - let traces = named_preprocessed_traces - .into_iter() - .map(|(_, trace)| trace) - .collect::>(); + let traces = + named_preprocessed_traces.into_iter().map(|(_, trace)| trace).collect::>(); let pc_start = program.pc_start(); @@ -227,15 +220,12 @@ impl>> StarkMachine { data, chip_ordering: chip_ordering.clone(), }, - StarkVerifyingKey { - commit, - pc_start, - chip_information, - chip_ordering, - }, + StarkVerifyingKey { commit, pc_start, chip_information, chip_ordering }, ) } + /// Generates the dependencies of the given records. + #[allow(clippy::needless_for_each)] pub fn generate_dependencies( &self, records: &mut [A::Record], @@ -251,15 +241,17 @@ impl>> StarkMachine { }); }); tracing::debug_span!("register nonces").in_scope(|| record.register_nonces(opts)); - }) + }); } + /// Returns the config of the machine. pub const fn config(&self) -> &SC { &self.config } /// Verify that a proof is complete and valid given a verifying key and a claimed digest. #[instrument("verify", level = "info", skip_all)] + #[allow(clippy::match_bool)] pub fn verify( &self, vk: &StarkVerifyingKey, @@ -287,9 +279,8 @@ impl>> StarkMachine { tracing::debug_span!("verify shard proofs").in_scope(|| { for (i, shard_proof) in proof.shard_proofs.iter().enumerate() { tracing::debug_span!("verifying shard", shard = i).in_scope(|| { - let chips = self - .shard_chips_ordered(&shard_proof.chip_ordering) - .collect::>(); + let chips = + self.shard_chips_ordered(&shard_proof.chip_ordering).collect::>(); Verifier::verify_shard( &self.config, vk, @@ -317,6 +308,7 @@ impl>> StarkMachine { }) } + /// Debugs the constraints of the given records. #[instrument("debug constraints", level = "debug", skip_all)] pub fn debug_constraints( &self, @@ -343,11 +335,7 @@ impl>> StarkMachine { // Generate the main trace for each chip. let pre_traces = chips .iter() - .map(|chip| { - pk.chip_ordering - .get(&chip.name()) - .map(|index| &pk.traces[*index]) - }) + .map(|chip| pk.chip_ordering.get(&chip.name()).map(|index| &pk.traces[*index])) .collect::>(); let mut traces = chips .par_iter() @@ -368,11 +356,8 @@ impl>> StarkMachine { main_trace, &permutation_challenges, ); - let cumulative_sum = perm_trace - .row_slice(main_trace.height() - 1) - .last() - .copied() - .unwrap(); + let cumulative_sum = + perm_trace.row_slice(main_trace.height() - 1).last().copied().unwrap(); (perm_trace, cumulative_sum) }) .unzip_into_vecs(&mut permutation_traces, &mut cumulative_sums); @@ -383,13 +368,15 @@ impl>> StarkMachine { // Compute some statistics. for i in 0..chips.len() { let trace_width = traces[i].0.width(); + let pre_width = traces[i].1.map_or(0, p3_matrix::Matrix::width); let permutation_width = permutation_traces[i].width() * >::D; - let total_width = trace_width + permutation_width; + let total_width = trace_width + pre_width + permutation_width; tracing::debug!( - "{:<11} | Main Cols = {:<5} | Perm Cols = {:<5} | Rows = {:<10} | Cells = {:<10}", + "{:<11} | Main Cols = {:<5} | Pre Cols = {:<5} | Perm Cols = {:<5} | Rows = {:<10} | Cells = {:<10}", chips[i].name(), trace_width, + pre_width, permutation_width, traces[i].0.height(), total_width * traces[i].0.height(), @@ -398,13 +385,11 @@ impl>> StarkMachine { tracing::info_span!("debug constraints").in_scope(|| { for i in 0..chips.len() { - let permutation_trace = pk - .chip_ordering - .get(&chips[i].name()) - .map(|index| &pk.traces[*index]); + let preprocessed_trace = + pk.chip_ordering.get(&chips[i].name()).map(|index| &pk.traces[*index]); debug_constraints::( chips[i], - permutation_trace, + preprocessed_trace, &traces[i].0, &permutation_traces[i], &permutation_challenges, @@ -414,6 +399,10 @@ impl>> StarkMachine { }); } + tracing::info!("Constraints verified successfully"); + + println!("Cumulative sum: {cumulative_sum}"); + // If the cumulative sum is not zero, debug the interactions. if !cumulative_sum.is_zero() { debug_interactions_with_all_chips::( @@ -427,21 +416,34 @@ impl>> StarkMachine { } } +/// Errors that can occur during machine verification. pub enum MachineVerificationError { + /// An error occurred during the verification of a shard proof. InvalidShardProof(VerificationError), + /// An error occurred during the verification of a global proof. InvalidGlobalProof(VerificationError), + /// The cumulative sum is non-zero. NonZeroCumulativeSum, + /// The public values digest is invalid. InvalidPublicValuesDigest, + /// The debug interactions failed. DebugInteractionsFailed, + /// The proof is empty. EmptyProof, + /// The public values are invalid. InvalidPublicValues(&'static str), + /// The number of shards is too large. TooManyShards, + /// The chip occurrence is invalid. InvalidChipOccurence(String), + /// The CPU is missing in the first shard. MissingCpuInFirstShard, + /// The CPU log degree is too large. CpuLogDegreeTooLarge(usize), } impl Debug for MachineVerificationError { + #[allow(clippy::uninlined_format_args)] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MachineVerificationError::InvalidShardProof(e) => { @@ -488,247 +490,3 @@ impl std::fmt::Display for MachineVerificationError } impl std::error::Error for MachineVerificationError {} - -#[cfg(test)] -#[allow(non_snake_case)] -pub mod tests { - - use crate::io::SP1Stdin; - use crate::runtime::tests::fibonacci_program; - use crate::runtime::tests::simple_memory_program; - use crate::runtime::tests::simple_program; - use crate::runtime::tests::ssz_withdrawals_program; - use crate::runtime::Instruction; - use crate::runtime::Opcode; - use crate::runtime::Program; - use crate::stark::CpuProver; - use crate::stark::RiscvAir; - use crate::stark::StarkProvingKey; - use crate::stark::StarkVerifyingKey; - use crate::utils; - use crate::utils::prove; - use crate::utils::run_test; - use crate::utils::setup_logger; - use crate::utils::BabyBearPoseidon2; - use crate::utils::SP1CoreOpts; - - #[test] - fn test_simple_prove() { - utils::setup_logger(); - let program = simple_program(); - run_test::>(program).unwrap(); - } - - #[test] - fn test_shift_prove() { - utils::setup_logger(); - let shift_ops = [Opcode::SRL, Opcode::SRA, Opcode::SLL]; - let operands = [ - (1, 1), - (1234, 5678), - (0xffff, 0xffff - 1), - (u32::MAX - 1, u32::MAX), - (u32::MAX, 0), - ]; - for shift_op in shift_ops.iter() { - for op in operands.iter() { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, op.0, false, true), - Instruction::new(Opcode::ADD, 30, 0, op.1, false, true), - Instruction::new(*shift_op, 31, 29, 3, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - } - } - - #[test] - fn test_sub_prove() { - utils::setup_logger(); - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 0, 8, false, true), - Instruction::new(Opcode::SUB, 31, 30, 29, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - - #[test] - fn test_add_prove() { - setup_logger(); - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 0, 8, false, true), - Instruction::new(Opcode::ADD, 31, 30, 29, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - - #[test] - fn test_mul_prove() { - let mul_ops = [Opcode::MUL, Opcode::MULH, Opcode::MULHU, Opcode::MULHSU]; - utils::setup_logger(); - let operands = [ - (1, 1), - (1234, 5678), - (8765, 4321), - (0xffff, 0xffff - 1), - (u32::MAX - 1, u32::MAX), - ]; - for mul_op in mul_ops.iter() { - for operand in operands.iter() { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, operand.0, false, true), - Instruction::new(Opcode::ADD, 30, 0, operand.1, false, true), - Instruction::new(*mul_op, 31, 30, 29, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - } - } - - #[test] - fn test_lt_prove() { - setup_logger(); - let less_than = [Opcode::SLT, Opcode::SLTU]; - for lt_op in less_than.iter() { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 0, 8, false, true), - Instruction::new(*lt_op, 31, 30, 29, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - } - - #[test] - fn test_bitwise_prove() { - setup_logger(); - let bitwise_opcodes = [Opcode::XOR, Opcode::OR, Opcode::AND]; - - for bitwise_op in bitwise_opcodes.iter() { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, 5, false, true), - Instruction::new(Opcode::ADD, 30, 0, 8, false, true), - Instruction::new(*bitwise_op, 31, 30, 29, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - } - - #[test] - fn test_divrem_prove() { - setup_logger(); - let div_rem_ops = [Opcode::DIV, Opcode::DIVU, Opcode::REM, Opcode::REMU]; - let operands = [ - (1, 1), - (123, 456 * 789), - (123 * 456, 789), - (0xffff * (0xffff - 1), 0xffff), - (u32::MAX - 5, u32::MAX - 7), - ]; - for div_rem_op in div_rem_ops.iter() { - for op in operands.iter() { - let instructions = vec![ - Instruction::new(Opcode::ADD, 29, 0, op.0, false, true), - Instruction::new(Opcode::ADD, 30, 0, op.1, false, true), - Instruction::new(*div_rem_op, 31, 29, 30, false, false), - ]; - let program = Program::new(instructions, 0, 0); - run_test::>(program).unwrap(); - } - } - } - - #[test] - fn test_fibonacci_prove_simple() { - setup_logger(); - let program = fibonacci_program(); - run_test::>(program).unwrap(); - } - - #[test] - fn test_fibonacci_prove_checkpoints() { - setup_logger(); - - let program = fibonacci_program(); - let stdin = SP1Stdin::new(); - let mut opts = SP1CoreOpts::default(); - opts.shard_size = 1024; - opts.shard_batch_size = 2; - prove::<_, CpuProver<_, _>>(program, &stdin, BabyBearPoseidon2::new(), opts).unwrap(); - } - - #[test] - fn test_fibonacci_prove_batch() { - setup_logger(); - let program = fibonacci_program(); - let stdin = SP1Stdin::new(); - prove::<_, CpuProver<_, _>>( - program, - &stdin, - BabyBearPoseidon2::new(), - SP1CoreOpts::default(), - ) - .unwrap(); - } - - #[test] - fn test_simple_memory_program_prove() { - setup_logger(); - let program = simple_memory_program(); - run_test::>(program).unwrap(); - } - - #[test] - fn test_ssz_withdrawal() { - setup_logger(); - let program = ssz_withdrawals_program(); - run_test::>(program).unwrap(); - } - - #[test] - fn test_key_serde() { - let program = ssz_withdrawals_program(); - let config = BabyBearPoseidon2::new(); - let machine = RiscvAir::machine(config); - let (pk, vk) = machine.setup(&program); - - let serialized_pk = bincode::serialize(&pk).unwrap(); - let deserialized_pk: StarkProvingKey = - bincode::deserialize(&serialized_pk).unwrap(); - assert_eq!(pk.commit, deserialized_pk.commit); - assert_eq!(pk.pc_start, deserialized_pk.pc_start); - assert_eq!(pk.traces, deserialized_pk.traces); - assert_eq!(pk.data.root(), deserialized_pk.data.root()); - assert_eq!(pk.chip_ordering, deserialized_pk.chip_ordering); - - let serialized_vk = bincode::serialize(&vk).unwrap(); - let deserialized_vk: StarkVerifyingKey = - bincode::deserialize(&serialized_vk).unwrap(); - assert_eq!(vk.commit, deserialized_vk.commit); - assert_eq!(vk.pc_start, deserialized_vk.pc_start); - assert_eq!( - vk.chip_information.len(), - deserialized_vk.chip_information.len() - ); - for (a, b) in vk - .chip_information - .iter() - .zip(deserialized_vk.chip_information.iter()) - { - assert_eq!(a.0, b.0); - assert_eq!(a.1.log_n, b.1.log_n); - assert_eq!(a.1.shift, b.1.shift); - assert_eq!(a.2.height, b.2.height); - assert_eq!(a.2.width, b.2.width); - } - assert_eq!(vk.chip_ordering, deserialized_vk.chip_ordering); - } -} diff --git a/core/src/utils/options.rs b/crates/stark/src/opts.rs similarity index 58% rename from core/src/utils/options.rs rename to crates/stark/src/opts.rs index 959feb8fe0..2c234579ad 100644 --- a/core/src/utils/options.rs +++ b/crates/stark/src/opts.rs @@ -2,8 +2,6 @@ use std::env; use serde::{Deserialize, Serialize}; -use crate::runtime::{SplitOpts, DEFERRED_SPLIT_THRESHOLD}; - const DEFAULT_SHARD_SIZE: usize = 1 << 22; const DEFAULT_SHARD_BATCH_SIZE: usize = 16; const DEFAULT_TRACE_GEN_WORKERS: usize = 1; @@ -13,27 +11,34 @@ const DEFAULT_RECORDS_AND_TRACES_CHANNEL_CAPACITY: usize = 1; /// Options to configure the SP1 prover for core and recursive proofs. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct SP1ProverOpts { + /// Options for the core prover. pub core_opts: SP1CoreOpts, + /// Options for the recursion prover. pub recursion_opts: SP1CoreOpts, } impl Default for SP1ProverOpts { fn default() -> Self { - Self { - core_opts: SP1CoreOpts::default(), - recursion_opts: SP1CoreOpts::recursion(), - } + Self { core_opts: SP1CoreOpts::default(), recursion_opts: SP1CoreOpts::recursion() } } } +/// Options for the core prover. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct SP1CoreOpts { + /// The size of a shard in terms of cycles. pub shard_size: usize, + /// The size of a batch of shards in terms of cycles. pub shard_batch_size: usize, + /// Options for splitting deferred events. pub split_opts: SplitOpts, + /// Whether to reconstruct the commitments. pub reconstruct_commitments: bool, + /// The number of workers to use for generating traces. pub trace_gen_workers: usize, + /// The capacity of the channel for checkpoints. pub checkpoints_channel_capacity: usize, + /// The capacity of the channel for records and traces. pub records_and_traces_channel_capacity: usize, } @@ -59,24 +64,20 @@ impl Default for SP1CoreOpts { ), checkpoints_channel_capacity: env::var("CHECKPOINTS_CHANNEL_CAPACITY").map_or_else( |_| DEFAULT_CHECKPOINTS_CHANNEL_CAPACITY, - |s| { - s.parse::() - .unwrap_or(DEFAULT_CHECKPOINTS_CHANNEL_CAPACITY) - }, + |s| s.parse::().unwrap_or(DEFAULT_CHECKPOINTS_CHANNEL_CAPACITY), ), records_and_traces_channel_capacity: env::var("RECORDS_AND_TRACES_CHANNEL_CAPACITY") .map_or_else( |_| DEFAULT_RECORDS_AND_TRACES_CHANNEL_CAPACITY, - |s| { - s.parse::() - .unwrap_or(DEFAULT_RECORDS_AND_TRACES_CHANNEL_CAPACITY) - }, + |s| s.parse::().unwrap_or(DEFAULT_RECORDS_AND_TRACES_CHANNEL_CAPACITY), ), } } } impl SP1CoreOpts { + /// Get the default options for the recursion prover. + #[must_use] pub fn recursion() -> Self { let mut opts = Self::default(); opts.reconstruct_commitments = false; @@ -84,3 +85,35 @@ impl SP1CoreOpts { opts } } + +/// Options for splitting deferred events. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct SplitOpts { + /// The threshold for default events. + pub deferred: usize, + /// The threshold for keccak events. + pub keccak: usize, + /// The threshold for sha extend events. + pub sha_extend: usize, + /// The threshold for sha compress events. + pub sha_compress: usize, + /// The threshold for memory events. + pub memory: usize, +} + +impl SplitOpts { + /// Create a new [`SplitOpts`] with the given threshold. + #[must_use] + pub fn new(deferred_shift_threshold: usize) -> Self { + Self { + deferred: deferred_shift_threshold, + keccak: deferred_shift_threshold / 24, + sha_extend: deferred_shift_threshold / 48, + sha_compress: deferred_shift_threshold / 80, + memory: deferred_shift_threshold * 4, + } + } +} + +/// The threshold for splitting deferred events. +pub const DEFERRED_SPLIT_THRESHOLD: usize = 1 << 19; diff --git a/core/src/stark/permutation.rs b/crates/stark/src/permutation.rs similarity index 74% rename from core/src/stark/permutation.rs rename to crates/stark/src/permutation.rs index ce27b9e9e7..583cb80641 100644 --- a/core/src/stark/permutation.rs +++ b/crates/stark/src/permutation.rs @@ -9,8 +9,17 @@ use rayon_scan::ScanParallelIterator; use crate::{air::MultiTableAirBuilder, lookup::Interaction}; +/// Computes the width of the permutation trace. +#[inline] +#[must_use] +pub const fn permutation_trace_width(num_interactions: usize, batch_size: usize) -> usize { + num_interactions.div_ceil(batch_size) + 1 +} + +/// Populates a permutation row. #[inline] #[allow(clippy::too_many_arguments)] +#[allow(clippy::needless_pass_by_value)] pub fn populate_permutation_row>( row: &mut [EF], preprocessed_row: &[F], @@ -26,6 +35,7 @@ pub fn populate_permutation_row>( .map(|int| (int, true)) .chain(receives.iter().map(|int| (int, false))) .chunks(batch_size); + // Compute the denominators \prod_{i\in B} row_fingerprint(alpha, beta). for (value, chunk) in row.iter_mut().zip(interaction_chunks) { *value = chunk @@ -36,11 +46,9 @@ pub fn populate_permutation_row>( denominator += betas.next().unwrap() * EF::from_canonical_usize(interaction.argument_index()); for (columns, beta) in interaction.values.iter().zip(betas) { - denominator += beta * columns.apply::(preprocessed_row, main_row) + denominator += beta * columns.apply::(preprocessed_row, main_row); } - let mut mult = interaction - .multiplicity - .apply::(preprocessed_row, main_row); + let mut mult = interaction.multiplicity.apply::(preprocessed_row, main_row); if !is_send { mult = -mult; @@ -52,14 +60,9 @@ pub fn populate_permutation_row>( } } -#[inline] -pub const fn permutation_trace_width(num_interactions: usize, batch_size: usize) -> usize { - num_interactions.div_ceil(batch_size) + 1 -} - -/// Generates the permutation trace for the given chip and main trace based on a variant of LogUp. +/// Generates the permutation trace for the given chip and main trace based on a variant of `LogUp`. /// -/// The permutation trace has (N+1)*EF::NUM_COLS columns, where N is the number of interactions in +/// The permutation trace has `(N+1)*EF::NUM_COLS` columns, where N is the number of interactions in /// the chip. pub fn generate_permutation_trace>( sends: &[Interaction], @@ -84,14 +87,12 @@ pub fn generate_permutation_trace>( // fingerprint for the interaction. let permutation_trace_width = permutation_trace_width(sends.len() + receives.len(), batch_size); let height = main.height(); - let mut permutation_trace = RowMajorMatrix::new( vec![EF::zero(); permutation_trace_width * height], permutation_trace_width, ); // Compute the permutation trace values in parallel. - match preprocessed { Some(prep) => { permutation_trace @@ -108,14 +109,12 @@ pub fn generate_permutation_trace>( alpha, betas.clone(), batch_size, - ) + ); }); } None => { - permutation_trace - .par_rows_mut() - .zip_eq(main.par_row_slices()) - .for_each(|(row, main_row)| { + permutation_trace.par_rows_mut().zip_eq(main.par_row_slices()).for_each( + |(row, main_row)| { populate_permutation_row( row, &[], @@ -125,33 +124,26 @@ pub fn generate_permutation_trace>( alpha, betas.clone(), batch_size, - ) - }); + ); + }, + ); } } let zero = EF::zero(); let cumulative_sums = permutation_trace .par_rows_mut() - .map(|row| { - row[0..permutation_trace_width - 1] - .iter() - .copied() - .sum::() - }) + .map(|row| row[0..permutation_trace_width - 1].iter().copied().sum::()) .collect::>(); - let cumulative_sums = cumulative_sums - .into_par_iter() - .scan(|a, b| *a + *b, zero) - .collect::>(); + let cumulative_sums = + cumulative_sums.into_par_iter().scan(|a, b| *a + *b, zero).collect::>(); - permutation_trace - .par_rows_mut() - .zip_eq(cumulative_sums.into_par_iter()) - .for_each(|(row, cumulative_sum)| { + permutation_trace.par_rows_mut().zip_eq(cumulative_sums.into_par_iter()).for_each( + |(row, cumulative_sum)| { *row.last_mut().unwrap() = cumulative_sum; - }); + }, + ); permutation_trace } @@ -172,19 +164,20 @@ pub fn eval_permutation_constraints( AB::EF: ExtensionField, AB: MultiTableAirBuilder + PairBuilder, { - let random_elements = builder.permutation_randomness(); + // Get the permutation challenges. + let permutation_challenges = builder.permutation_randomness(); let (alpha, beta): (AB::ExprEF, AB::ExprEF) = - (random_elements[0].into(), random_elements[1].into()); + (permutation_challenges[0].into(), permutation_challenges[1].into()); + // Get the preprocssed, main, and permutation trace. + let preprocessed = builder.preprocessed(); let main = builder.main(); + let perm = builder.permutation().to_row_major_matrix(); + + let preprocessed_local = preprocessed.row_slice(0); let main_local = main.to_row_major_matrix(); let main_local = main_local.row_slice(0); let main_local: &[AB::Var] = (*main_local).borrow(); - - let preprocessed = builder.preprocessed(); - let preprocessed_local = preprocessed.row_slice(0); - - let perm = builder.permutation().to_row_major_matrix(); let perm_width = perm.width(); let perm_local = perm.row_slice(0); let perm_local: &[AB::VarEF] = (*perm_local).borrow(); @@ -198,27 +191,18 @@ pub fn eval_permutation_constraints( .chain(receives.iter().map(|int| (int, false))) .chunks(batch_size); - assert_eq!( - interaction_chunks.into_iter().count(), - perm_width - 1, - "Number of sends: {}, receives: {}, batch size: {}, perm width: {}", - sends.len(), - receives.len(), - batch_size, - perm_width - 1 - ); - assert_eq!( - perm_width, - permutation_trace_width(sends.len() + receives.len(), batch_size) - ); - - for (entry, chunk) in perm_local[0..perm_local.len() - 1] - .iter() - .zip(interaction_chunks) - { - // Assert that the i-eth entry is equal to the sum_i m_i/rlc_i by constraints: - // entry * \prod_i rlc_i = \sum_i m_i * \prod_{j!=i} rlc_j. + // Assert that the permutation trace width is correct. + let expected_perm_width = permutation_trace_width(sends.len() + receives.len(), batch_size); + if perm_width != expected_perm_width { + panic!( + "permutation trace width is incorrect: expected {expected_perm_width}, got {perm_width}", + ); + } + // Assert that the i-eth entry is equal to the sum_i m_i/rlc_i by constraints: + // entry * \prod_i rlc_i = \sum_i m_i * \prod_{j!=i} rlc_j over all columns of the permutation + // trace except the last column. + for (entry, chunk) in perm_local[0..perm_local.len() - 1].iter().zip(interaction_chunks) { // First, we calculate the random linear combinations and multiplicities with the correct // sign depending on wetther the interaction is a send or a recieve. let mut rlcs: Vec = Vec::with_capacity(batch_size); @@ -226,6 +210,7 @@ pub fn eval_permutation_constraints( for (interaction, is_send) in chunk { let mut rlc = alpha.clone(); let mut betas = beta.powers(); + rlc += betas.next().unwrap() * AB::ExprEF::from_canonical_usize(interaction.argument_index()); for (field, beta) in interaction.values.iter().zip(betas.clone()) { @@ -249,14 +234,10 @@ pub fn eval_permutation_constraints( for (i, (m, rlc)) in multiplicities.into_iter().zip(rlcs.iter()).enumerate() { // Calculate the running product of all rlcs. product *= rlc.clone(); + // Calculate the product of all but the current rlc. let mut all_but_current = AB::ExprEF::one(); - for other_rlc in rlcs - .iter() - .enumerate() - .filter(|(j, _)| i != *j) - .map(|(_, rlc)| rlc) - { + for other_rlc in rlcs.iter().enumerate().filter(|(j, _)| i != *j).map(|(_, rlc)| rlc) { all_but_current *= other_rlc.clone(); } numerator += AB::ExprEF::from_base(m) * all_but_current; @@ -267,26 +248,20 @@ pub fn eval_permutation_constraints( builder.assert_eq_ext(product.clone() * entry.clone(), numerator); } - let sum_local = perm_local[..perm_width - 1] - .iter() - .map(|x| (*x).into()) - .sum::(); - - let sum_next = perm_next[..perm_width - 1] - .iter() - .map(|x| (*x).into()) - .sum::(); - + // Compute the running local and next permutation sums. + let cumulative_sum = builder.cumulative_sum(); + let sum_local = perm_local[..perm_width - 1].iter().map(|x| (*x).into()).sum::(); + let sum_next = perm_next[..perm_width - 1].iter().map(|x| (*x).into()).sum::(); let phi_local: AB::ExprEF = (*perm_local.last().unwrap()).into(); let phi_next: AB::ExprEF = (*perm_next.last().unwrap()).into(); - builder - .when_transition() - .assert_eq_ext(phi_next - phi_local.clone(), sum_next); - builder.when_first_row().assert_eq_ext(phi_local, sum_local); + // Assert that cumulative sum is initialized to `phi_local` on the first row. + builder.when_first_row().assert_eq_ext(phi_local.clone(), sum_local); - let cumulative_sum = builder.cumulative_sum(); - builder - .when_last_row() - .assert_eq_ext(*perm_local.last().unwrap(), cumulative_sum); + // Assert that the cumulative sum is constrained to `phi_next - phi_local` on the transition + // rows. + builder.when_transition().assert_eq_ext(phi_next - phi_local.clone(), sum_next); + + // Assert that the cumulative sum is constrained to `phi_local` on the last row. + builder.when_last_row().assert_eq_ext(*perm_local.last().unwrap(), cumulative_sum); } diff --git a/core/src/stark/prover.rs b/crates/stark/src/prover.rs similarity index 76% rename from core/src/stark/prover.rs rename to crates/stark/src/prover.rs index 14482121fe..d3839b3f57 100644 --- a/core/src/stark/prover.rs +++ b/crates/stark/src/prover.rs @@ -1,36 +1,28 @@ use core::fmt::Display; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::cmp::Reverse; -use std::error::Error; - use itertools::Itertools; +use serde::{de::DeserializeOwned, Serialize}; +use std::{cmp::Reverse, error::Error, time::Instant}; + +use crate::{AirOpenedValues, ChipOpenedValues, ShardOpenedValues}; use p3_air::Air; use p3_challenger::{CanObserve, FieldChallenger}; -use p3_commit::Pcs; -use p3_commit::PolynomialSpace; -use p3_field::PrimeField32; -use p3_field::{AbstractExtensionField, AbstractField}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; +use p3_commit::{Pcs, PolynomialSpace}; +use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; +use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::*; use p3_util::log2_strict_usize; -use super::{quotient_values, StarkMachine, Val}; -use super::{types::*, StarkGenericConfig}; -use super::{Com, OpeningProof}; -use super::{StarkProvingKey, VerifierConstraintFolder}; -use crate::air::MachineAir; -use crate::lookup::InteractionBuilder; -use crate::stark::record::MachineRecord; -use crate::stark::DebugConstraintBuilder; -use crate::stark::MachineChip; -use crate::stark::PackedChallenge; -use crate::stark::PcsProverData; -use crate::stark::ProverConstraintFolder; -use crate::stark::StarkVerifyingKey; -use crate::utils::SP1CoreOpts; - +use super::{ + quotient_values, Com, OpeningProof, StarkGenericConfig, StarkMachine, StarkProvingKey, Val, + VerifierConstraintFolder, +}; +use crate::{ + air::MachineAir, lookup::InteractionBuilder, opts::SP1CoreOpts, record::MachineRecord, + DebugConstraintBuilder, MachineChip, MachineProof, PackedChallenge, PcsProverData, + ProverConstraintFolder, ShardCommitment, ShardMainData, ShardProof, StarkVerifyingKey, +}; + +/// An algorithmic & hardware independent prover implementation for any [`MachineAir`]. pub trait MachineProver>: 'static + Send + Sync { @@ -62,16 +54,22 @@ pub trait MachineProver>: // For each chip, generate the trace. let parent_span = tracing::debug_span!("generate traces for shard"); parent_span.in_scope(|| { - shard_chips - .par_iter() - .map(|chip| { - let chip_name = chip.name(); - let trace = tracing::debug_span!(parent: &parent_span, "generate trace for chip", %chip_name) - .in_scope(|| chip.generate_trace(record, &mut A::Record::default())); - (chip_name, trace) - }) - .collect::>() - }) + shard_chips + .par_iter() + .map(|chip| { + let chip_name = chip.name(); + let begin = Instant::now(); + let trace = chip.generate_trace(record, &mut A::Record::default()); + tracing::debug!( + parent: &parent_span, + "generated trace for chip {} in {:?}", + chip_name, + begin.elapsed() + ); + (chip_name, trace) + }) + .collect::>() + }) } /// Commit to the main traces. @@ -146,14 +144,16 @@ pub trait MachineProver>: SC::Val: PrimeField32, A: for<'a> Air, SC::Challenge>>, { - self.machine().debug_constraints(pk, records, challenger) + self.machine().debug_constraints(pk, records, challenger); } } +/// A prover implementation based on x86 and ARM CPUs. pub struct CpuProver { machine: StarkMachine, } +/// An error that occurs during the execution of the [`CpuProver`]. #[derive(Debug, Clone, Copy)] pub struct CpuProverError; @@ -205,16 +205,10 @@ where let (main_commit, main_data) = pcs.commit(domains_and_traces); // Get the chip ordering. - let chip_ordering = named_traces - .iter() - .enumerate() - .map(|(i, (name, _))| (name.to_owned(), i)) - .collect(); + let chip_ordering = + named_traces.iter().enumerate().map(|(i, (name, _))| (name.to_owned(), i)).collect(); - let traces = named_traces - .into_iter() - .map(|(_, trace)| trace) - .collect::>(); + let traces = named_traces.into_iter().map(|(_, trace)| trace).collect::>(); ShardMainData { traces, @@ -226,40 +220,31 @@ where } /// Prove the program for the given shard and given a commitment to the main data. + #[allow(clippy::too_many_lines)] + #[allow(clippy::redundant_closure_for_method_calls)] + #[allow(clippy::map_unwrap_or)] fn open( &self, pk: &StarkProvingKey, mut data: ShardMainData, challenger: &mut ::Challenger, ) -> Result, Self::Error> { - let chips = self - .machine() - .shard_chips_ordered(&data.chip_ordering) - .collect::>(); + let chips = self.machine().shard_chips_ordered(&data.chip_ordering).collect::>(); let config = self.machine().config(); // Get the traces. let traces = &mut data.traces; - let degrees = traces - .iter() - .map(|trace| trace.height()) - .collect::>(); + let degrees = traces.iter().map(|trace| trace.height()).collect::>(); - let log_degrees = degrees - .iter() - .map(|degree| log2_strict_usize(*degree)) - .collect::>(); + let log_degrees = + degrees.iter().map(|degree| log2_strict_usize(*degree)).collect::>(); - let log_quotient_degrees = chips - .iter() - .map(|chip| chip.log_quotient_degree()) - .collect::>(); + let log_quotient_degrees = + chips.iter().map(|chip| chip.log_quotient_degree()).collect::>(); let pcs = config.pcs(); - let trace_domains = degrees - .iter() - .map(|degree| pcs.natural_domain_for_degree(*degree)) - .collect::>(); + let trace_domains = + degrees.iter().map(|degree| pcs.natural_domain_for_degree(*degree)).collect::>(); // Obtain the challenges used for the permutation argument. let mut permutation_challenges: Vec = Vec::new(); @@ -272,42 +257,39 @@ where .collect::>(); // Generate the permutation traces. - let mut permutation_traces = Vec::with_capacity(chips.len()); - let mut cumulative_sums = Vec::with_capacity(chips.len()); - tracing::debug_span!("generate permutation traces").in_scope(|| { - chips - .par_iter() - .zip(traces.par_iter_mut()) - .map(|(chip, main_trace)| { - let preprocessed_trace = pk - .chip_ordering - .get(&chip.name()) - .map(|&index| &pk.traces[index]); - let perm_trace = chip.generate_permutation_trace( - preprocessed_trace, - main_trace, - &permutation_challenges, - ); - let cumulative_sum = perm_trace - .row_slice(main_trace.height() - 1) - .last() - .copied() - .unwrap(); - (perm_trace, cumulative_sum) - }) - .unzip_into_vecs(&mut permutation_traces, &mut cumulative_sums); - }); + let ((permutation_traces, prep_traces), cumulative_sums): ((Vec<_>, Vec<_>), Vec<_>) = + tracing::debug_span!("generate permutation traces").in_scope(|| { + chips + .par_iter() + .zip(traces.par_iter_mut()) + .map(|(chip, main_trace): (&&MachineChip, _)| { + let preprocessed_trace = + pk.chip_ordering.get(&chip.name()).map(|&index| &pk.traces[index]); + let perm_trace = chip.generate_permutation_trace( + preprocessed_trace, + main_trace, + &permutation_challenges, + ); + let cumulative_sum = + perm_trace.row_slice(main_trace.height() - 1).last().copied().unwrap(); + ((perm_trace, preprocessed_trace), cumulative_sum) + }) + .unzip() + }); // Compute some statistics. for i in 0..chips.len() { let trace_width = traces[i].width(); + let prep_width = prep_traces[i].map_or(0, |x| x.width()); let permutation_width = permutation_traces[i].width(); let total_width = trace_width + + prep_width + permutation_width * >::D; tracing::debug!( - "{:<15} | Main Cols = {:<5} | Perm Cols = {:<5} | Rows = {:<5} | Cells = {:<10}", + "{:<15} | Main Cols = {:<5} | Pre Cols = {:<5} | Perm Cols = {:<5} | Rows = {:<5} | Cells = {:<10}", chips[i].name(), trace_width, + prep_width, permutation_width * >::D, traces[i].height(), total_width * traces[i].height(), @@ -321,7 +303,7 @@ where .zip(trace_domains.iter()) .map(|(perm_trace, domain)| { let trace = perm_trace.flatten_to_base(); - (*domain, trace.to_owned()) + (*domain, trace.clone()) }) .collect::>() }); @@ -395,25 +377,19 @@ where .into_iter() .zip_eq(quotient_values) .zip_eq(log_quotient_degrees.iter()) - .flat_map( - |((quotient_domain, quotient_values), log_quotient_degree)| { - let quotient_degree = 1 << *log_quotient_degree; - let quotient_flat = RowMajorMatrix::new_col(quotient_values).flatten_to_base(); - let quotient_chunks = - quotient_domain.split_evals(quotient_degree, quotient_flat); - let qc_domains = quotient_domain.split_domains(quotient_degree); - qc_domains.into_iter().zip_eq(quotient_chunks) - }, - ) + .flat_map(|((quotient_domain, quotient_values), log_quotient_degree)| { + let quotient_degree = 1 << *log_quotient_degree; + let quotient_flat = RowMajorMatrix::new_col(quotient_values).flatten_to_base(); + let quotient_chunks = quotient_domain.split_evals(quotient_degree, quotient_flat); + let qc_domains = quotient_domain.split_domains(quotient_degree); + qc_domains.into_iter().zip_eq(quotient_chunks) + }) .collect::>(); let num_quotient_chunks = quotient_domains_and_chunks.len(); assert_eq!( num_quotient_chunks, - chips - .iter() - .map(|c| 1 << c.log_quotient_degree()) - .sum::() + chips.iter().map(|c| 1 << c.log_quotient_degree()).sum::() ); let (quotient_commit, quotient_data) = tracing::debug_span!("commit to quotient traces") @@ -443,9 +419,8 @@ where }); // Compute quotient openning points, open every chunk at zeta. - let quotient_opening_points = (0..num_quotient_chunks) - .map(|_| vec![zeta]) - .collect::>(); + let quotient_opening_points = + (0..num_quotient_chunks).map(|_| vec![zeta]).collect::>(); let (openings, opening_proof) = tracing::debug_span!("open multi batches").in_scope(|| { pcs.open( @@ -499,26 +474,21 @@ where .zip_eq(cumulative_sums) .zip_eq(log_degrees.iter()) .enumerate() - .map( - |(i, ((((main, permutation), quotient), cumulative_sum), log_degree))| { - let preprocessed = pk - .chip_ordering - .get(&chips[i].name()) - .map(|&index| preprocessed_opened_values[index].clone()) - .unwrap_or(AirOpenedValues { - local: vec![], - next: vec![], - }); - ChipOpenedValues { - preprocessed, - main, - permutation, - quotient, - cumulative_sum, - log_degree: *log_degree, - } - }, - ) + .map(|(i, ((((main, permutation), quotient), cumulative_sum), log_degree))| { + let preprocessed = pk + .chip_ordering + .get(&chips[i].name()) + .map(|&index| preprocessed_opened_values[index].clone()) + .unwrap_or(AirOpenedValues { local: vec![], next: vec![] }); + ChipOpenedValues { + preprocessed, + main, + permutation, + quotient, + cumulative_sum, + log_degree: *log_degree, + } + }) .collect::>(); Ok(ShardProof:: { @@ -527,9 +497,7 @@ where permutation_commit, quotient_commit, }, - opened_values: ShardOpenedValues { - chips: opened_values, - }, + opened_values: ShardOpenedValues { chips: opened_values }, opening_proof, chip_ordering: data.chip_ordering, public_values: data.public_values, @@ -540,6 +508,7 @@ where /// /// Given a proving key `pk` and a matching execution record `record`, this function generates /// a STARK proof that the execution record is valid. + #[allow(clippy::needless_for_each)] fn prove( &self, pk: &StarkProvingKey, diff --git a/core/src/stark/quotient.rs b/crates/stark/src/quotient.rs similarity index 94% rename from core/src/stark/quotient.rs rename to crates/stark/src/quotient.rs index b42d386994..8bf903f77a 100644 --- a/core/src/stark/quotient.rs +++ b/crates/stark/src/quotient.rs @@ -1,25 +1,21 @@ use p3_air::Air; use p3_commit::PolynomialSpace; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; -use p3_field::PackedValue; -use p3_matrix::dense::RowMajorMatrixView; -use p3_matrix::stack::VerticalPair; -use p3_matrix::Matrix; +use p3_field::{AbstractExtensionField, AbstractField, PackedValue}; +use p3_matrix::{dense::RowMajorMatrixView, stack::VerticalPair, Matrix}; use p3_maybe_rayon::prelude::*; use p3_util::log2_strict_usize; use crate::air::MachineAir; -use super::folder::ProverConstraintFolder; -use super::Chip; -use super::Domain; -use super::PackedChallenge; -use super::PackedVal; -use super::StarkGenericConfig; -use super::Val; +use super::{ + folder::ProverConstraintFolder, Chip, Domain, PackedChallenge, PackedVal, StarkGenericConfig, + Val, +}; +/// Computes the quotient values. +#[allow(clippy::needless_pass_by_value)] #[allow(clippy::too_many_arguments)] +#[allow(clippy::too_many_lines)] pub fn quotient_values( chip: &Chip, A>, cumulative_sum: SC::Challenge, diff --git a/core/src/stark/record.rs b/crates/stark/src/record.rs similarity index 59% rename from core/src/stark/record.rs rename to crates/stark/src/record.rs index a82a77ce6b..5676b75b52 100644 --- a/core/src/stark/record.rs +++ b/crates/stark/src/record.rs @@ -2,14 +2,20 @@ use hashbrown::HashMap; use p3_field::AbstractField; +/// A record that can be proven by a machine. pub trait MachineRecord: Default + Sized + Send + Sync + Clone { + /// The configuration of the machine. type Config: 'static + Copy + Send + Sync; + /// The statistics of the record. fn stats(&self) -> HashMap; + /// Appends two records together. fn append(&mut self, other: &mut Self); + /// Registers the nonces of the record. fn register_nonces(&mut self, _opts: &Self::Config) {} + /// Returns the public values of the record. fn public_values(&self) -> Vec; } diff --git a/core/src/stark/types.rs b/crates/stark/src/types.rs similarity index 81% rename from core/src/stark/types.rs rename to crates/stark/src/types.rs index 2b52572a66..822a7a6268 100644 --- a/core/src/stark/types.rs +++ b/crates/stark/src/types.rs @@ -1,8 +1,9 @@ +#![allow(missing_docs)] + use std::fmt::Debug; use hashbrown::HashMap; -use p3_matrix::dense::RowMajorMatrixView; -use p3_matrix::stack::VerticalPair; +use p3_matrix::{dense::RowMajorMatrixView, stack::VerticalPair}; use serde::{Deserialize, Serialize}; use super::{Challenge, Com, OpeningProof, StarkGenericConfig, Val}; @@ -25,13 +26,7 @@ impl ShardMainData { chip_ordering: HashMap, public_values: Vec>, ) -> Self { - Self { - traces, - main_commit, - main_data, - chip_ordering, - public_values, - } + Self { traces, main_commit, main_data, chip_ordering, public_values } } } @@ -63,9 +58,9 @@ pub struct ShardOpenedValues { pub chips: Vec>, } -/// The maximum number of elements that can be stored in the public values vec. Both SP1 and recursive -/// proofs need to pad their public_values vec to this length. This is required since the recursion -/// verification program expects the public values vec to be fixed length. +/// The maximum number of elements that can be stored in the public values vec. Both SP1 and +/// recursive proofs need to pad their public values vec to this length. This is required since the +/// recursion verification program expects the public values vec to be fixed length. pub const PROOF_MAX_NUM_PVS: usize = 370; #[derive(Serialize, Deserialize, Clone)] @@ -85,6 +80,7 @@ impl Debug for ShardProof { } impl AirOpenedValues { + #[must_use] pub fn view(&self) -> VerticalPair, RowMajorMatrixView<'_, T>> { let a = RowMajorMatrixView::new_row(&self.local); let b = RowMajorMatrixView::new_row(&self.next); @@ -94,11 +90,7 @@ impl AirOpenedValues { impl ShardProof { pub fn cumulative_sum(&self) -> Challenge { - self.opened_values - .chips - .iter() - .map(|c| c.cumulative_sum) - .sum() + self.opened_values.chips.iter().map(|c| c.cumulative_sum).sum() } pub fn log_degree_cpu(&self) -> usize { @@ -127,13 +119,11 @@ pub struct MachineProof { impl Debug for MachineProof { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Proof") - .field("shard_proofs", &self.shard_proofs.len()) - .finish() + f.debug_struct("Proof").field("shard_proofs", &self.shard_proofs.len()).finish() } } -/// PublicValuesDigest is a hash of all the public values that a zkvm program has committed to. +/// The hash of all the public values that a zkvm program has committed to. pub struct PublicValuesDigest(pub [u8; 32]); impl From<[u32; 8]> for PublicValuesDigest { @@ -146,7 +136,7 @@ impl From<[u32; 8]> for PublicValuesDigest { } } -/// DeferredDigest is a hash of all the deferred proofs that have been witnessed in the VM. +/// The hash of all the deferred proofs that have been witnessed in the VM. pub struct DeferredDigest(pub [u8; 32]); impl From<[u32; 8]> for DeferredDigest { diff --git a/core/src/stark/util.rs b/crates/stark/src/util.rs similarity index 93% rename from core/src/stark/util.rs rename to crates/stark/src/util.rs index 8ba06e98fb..c0a2be0177 100644 --- a/core/src/stark/util.rs +++ b/crates/stark/src/util.rs @@ -6,7 +6,7 @@ pub fn batch_multiplicative_inverse_inplace(values: &mut [F]) { // Check if values are zero and construct a new vector with only nonzero values. let mut nonzero_values = Vec::with_capacity(values.len()); let mut indices = Vec::with_capacity(values.len()); - for (i, value) in values.iter().cloned().enumerate() { + for (i, value) in values.iter().copied().enumerate() { if value.is_zero() { continue; } diff --git a/core/src/stark/verifier.rs b/crates/stark/src/verifier.rs similarity index 82% rename from core/src/stark/verifier.rs rename to crates/stark/src/verifier.rs index f1b51aaba8..43bbf61798 100644 --- a/core/src/stark/verifier.rs +++ b/crates/stark/src/verifier.rs @@ -1,33 +1,28 @@ use core::fmt::Display; -use std::fmt::Debug; -use std::fmt::Formatter; -use std::marker::PhantomData; +use std::{ + fmt::{Debug, Formatter}, + marker::PhantomData, +}; use itertools::Itertools; -use p3_air::Air; -use p3_air::BaseAir; -use p3_challenger::CanObserve; -use p3_challenger::FieldChallenger; -use p3_commit::LagrangeSelectors; -use p3_commit::Pcs; -use p3_commit::PolynomialSpace; -use p3_field::AbstractExtensionField; -use p3_field::AbstractField; - -use super::folder::VerifierConstraintFolder; -use super::types::*; -use super::Domain; -use super::OpeningError; -use super::StarkGenericConfig; -use super::StarkVerifyingKey; -use super::Val; -use crate::air::MachineAir; -use crate::stark::MachineChip; - +use p3_air::{Air, BaseAir}; +use p3_challenger::{CanObserve, FieldChallenger}; +use p3_commit::{LagrangeSelectors, Pcs, PolynomialSpace}; +use p3_field::{AbstractExtensionField, AbstractField}; + +use super::{ + folder::VerifierConstraintFolder, + types::{AirOpenedValues, ChipOpenedValues, ShardCommitment, ShardProof}, + Domain, OpeningError, StarkGenericConfig, StarkVerifyingKey, Val, +}; +use crate::{air::MachineAir, MachineChip}; + +/// A verifier for a collection of air chips. pub struct Verifier(PhantomData, PhantomData); impl>> Verifier { /// Verify a proof for a collection of air chips. + #[allow(clippy::too_many_lines)] pub fn verify_shard( config: &SC, vk: &StarkVerifyingKey, @@ -55,31 +50,20 @@ impl>> Verifier { return Err(VerificationError::ChipOpeningLengthMismatch); } - let log_degrees = opened_values - .chips - .iter() - .map(|val| val.log_degree) - .collect::>(); + let log_degrees = opened_values.chips.iter().map(|val| val.log_degree).collect::>(); - let log_quotient_degrees = chips - .iter() - .map(|chip| chip.log_quotient_degree()) - .collect::>(); + let log_quotient_degrees = + chips.iter().map(|chip| chip.log_quotient_degree()).collect::>(); let trace_domains = log_degrees .iter() .map(|log_degree| pcs.natural_domain_for_degree(1 << log_degree)) .collect::>(); - let ShardCommitment { - main_commit, - permutation_commit, - quotient_commit, - } = commitment; + let ShardCommitment { main_commit, permutation_commit, quotient_commit } = commitment; - let permutation_challenges = (0..2) - .map(|_| challenger.sample_ext_element::()) - .collect::>(); + let permutation_challenges = + (0..2).map(|_| challenger.sample_ext_element::()).collect::>(); challenger.observe(permutation_commit.clone()); @@ -98,10 +82,7 @@ impl>> Verifier { let values = opened_values.chips[i].preprocessed.clone(); ( *domain, - vec![ - (zeta, values.local), - (domain.next_point(zeta).unwrap(), values.next), - ], + vec![(zeta, values.local), (domain.next_point(zeta).unwrap(), values.next)], ) }) .collect::>(); @@ -128,10 +109,7 @@ impl>> Verifier { *domain, vec![ (zeta, values.permutation.local.clone()), - ( - domain.next_point(zeta).unwrap(), - values.permutation.next.clone(), - ), + (domain.next_point(zeta).unwrap(), values.permutation.next.clone()), ], ) }) @@ -178,12 +156,9 @@ impl>> Verifier { .map_err(|e| VerificationError::InvalidopeningArgument(e))?; // Verify the constrtaint evaluations. - for (chip, trace_domain, qc_domains, values) in izip!( - chips.iter(), - trace_domains, - quotient_chunk_domains, - opened_values.chips.iter(), - ) { + for (chip, trace_domain, qc_domains, values) in + izip!(chips.iter(), trace_domains, quotient_chunk_domains, opened_values.chips.iter(),) + { // Verify the shape of the opening arguments matches the expected values. Self::verify_opening_shape(chip, values) .map_err(|e| VerificationError::OpeningShapeError(chip.name(), e))?; @@ -272,6 +247,7 @@ impl>> Verifier { } #[allow(clippy::too_many_arguments)] + #[allow(clippy::needless_pass_by_value)] fn verify_constraints( chip: &MachineChip, opening: &ChipOpenedValues, @@ -301,12 +277,14 @@ impl>> Verifier { // Check that the constraints match the quotient, i.e. // folded_constraints(zeta) / Z_H(zeta) = quotient(zeta) - match folded_constraints * sels.inv_zeroifier == quotient { - true => Ok(()), - false => Err(OodEvaluationMismatch), + if folded_constraints * sels.inv_zeroifier == quotient { + Ok(()) + } else { + Err(OodEvaluationMismatch) } } + /// Evaluates the constraints for a chip and opening. pub fn eval_constraints( chip: &MachineChip, opening: &ChipOpenedValues, @@ -322,11 +300,7 @@ impl>> Verifier { let unflatten = |v: &[SC::Challenge]| { v.chunks_exact(SC::Challenge::D) .map(|chunk| { - chunk - .iter() - .enumerate() - .map(|(e_i, &x)| SC::Challenge::monomial(e_i) * x) - .sum() + chunk.iter().enumerate().map(|(e_i, &x)| SC::Challenge::monomial(e_i) * x).sum() }) .collect::>() }; @@ -356,6 +330,7 @@ impl>> Verifier { folder.accumulator } + /// Recomputes the quotient for a chip and opening. pub fn recompute_quotient( opening: &ChipOpenedValues, qc_domains: &[Domain], @@ -394,16 +369,24 @@ impl>> Verifier { } } +/// An error that occurs when the openings do not match the expected shape. pub struct OodEvaluationMismatch; +/// An error that occurs when the shape of the openings does not match the expected shape. pub enum OpeningShapeError { + /// The width of the preprocessed trace does not match the expected width. PreprocessedWidthMismatch(usize, usize), + /// The width of the main trace does not match the expected width. MainWidthMismatch(usize, usize), + /// The width of the permutation trace does not match the expected width. PermutationWidthMismatch(usize, usize), + /// The width of the quotient trace does not match the expected width. QuotientWidthMismatch(usize, usize), + /// The chunk size of the quotient trace does not match the expected chunk size. QuotientChunkSizeMismatch(usize, usize), } +/// An error that occurs during the verification. pub enum VerificationError { /// opening proof is invalid. InvalidopeningArgument(OpeningError), @@ -413,47 +396,30 @@ pub enum VerificationError { OodEvaluationMismatch(String), /// The shape of the opening arguments is invalid. OpeningShapeError(String, OpeningShapeError), + /// The cpu chip is missing. MissingCpuChip, + /// The length of the chip opening does not match the expected length. ChipOpeningLengthMismatch, } impl Debug for OpeningShapeError { + #[allow(clippy::uninlined_format_args)] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { OpeningShapeError::PreprocessedWidthMismatch(expected, actual) => { - write!( - f, - "Preprocessed width mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Preprocessed width mismatch: expected {}, got {}", expected, actual) } OpeningShapeError::MainWidthMismatch(expected, actual) => { - write!( - f, - "Main width mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Main width mismatch: expected {}, got {}", expected, actual) } OpeningShapeError::PermutationWidthMismatch(expected, actual) => { - write!( - f, - "Permutation width mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Permutation width mismatch: expected {}, got {}", expected, actual) } OpeningShapeError::QuotientWidthMismatch(expected, actual) => { - write!( - f, - "Quotient width mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Quotient width mismatch: expected {}, got {}", expected, actual) } OpeningShapeError::QuotientChunkSizeMismatch(expected, actual) => { - write!( - f, - "Quotient chunk size mismatch: expected {}, got {}", - expected, actual - ) + write!(f, "Quotient chunk size mismatch: expected {}, got {}", expected, actual) } } } @@ -461,12 +427,12 @@ impl Debug for OpeningShapeError { impl Display for OpeningShapeError { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - // use the debug implementation - write!(f, "{:?}", self) + write!(f, "{self:?}") } } impl Debug for VerificationError { + #[allow(clippy::uninlined_format_args)] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { VerificationError::InvalidopeningArgument(e) => { @@ -489,6 +455,7 @@ impl Debug for VerificationError { } impl Display for VerificationError { + #[allow(clippy::uninlined_format_args)] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { VerificationError::InvalidopeningArgument(_) => { diff --git a/core/src/air/word.rs b/crates/stark/src/word.rs similarity index 73% rename from core/src/air/word.rs rename to crates/stark/src/word.rs index dbc07a12c9..456a8b0095 100644 --- a/core/src/air/word.rs +++ b/crates/stark/src/word.rs @@ -1,21 +1,19 @@ -use core::fmt::Debug; -use std::array::IntoIter; use std::ops::{Index, IndexMut}; +use crate::air::SP1AirBuilder; use arrayref::array_ref; use itertools::Itertools; use p3_air::AirBuilder; -use p3_field::AbstractField; -use p3_field::Field; +use p3_field::{AbstractField, Field}; use serde::{Deserialize, Serialize}; use sp1_derive::AlignedBorrow; +use sp1_primitives::consts::WORD_SIZE; +use std::array::IntoIter; -use super::SP1AirBuilder; - -/// The size of a word in bytes. -pub const WORD_SIZE: usize = 4; - -/// A word is a 32-bit value represented in an AIR. +/// An array of four bytes to represent a 32-bit value. +/// +/// We use the generic type `T` to represent the different representations of a byte, ranging from +/// a `u8` to a `AB::Var` or `AB::Expr`. #[derive( AlignedBorrow, Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize, )] @@ -33,34 +31,20 @@ impl Word { /// Extends a variable to a word. pub fn extend_var>(var: T) -> Word { - Word([ - AB::Expr::zero() + var, - AB::Expr::zero(), - AB::Expr::zero(), - AB::Expr::zero(), - ]) + Word([AB::Expr::zero() + var, AB::Expr::zero(), AB::Expr::zero(), AB::Expr::zero()]) } } impl Word { /// Extends a variable to a word. pub fn extend_expr>(expr: T) -> Word { - Word([ - AB::Expr::zero() + expr, - AB::Expr::zero(), - AB::Expr::zero(), - AB::Expr::zero(), - ]) + Word([AB::Expr::zero() + expr, AB::Expr::zero(), AB::Expr::zero(), AB::Expr::zero()]) } /// Returns a word with all zero expressions. + #[must_use] pub fn zero>() -> Word { - Word([ - AB::Expr::zero(), - AB::Expr::zero(), - AB::Expr::zero(), - AB::Expr::zero(), - ]) + Word([AB::Expr::zero(), AB::Expr::zero(), AB::Expr::zero(), AB::Expr::zero()]) } } @@ -75,11 +59,7 @@ impl Word { /// Reduces a word to a single variable. pub fn reduce>(&self) -> AB::Expr { let base = [1, 1 << 8, 1 << 16, 1 << 24].map(AB::Expr::from_canonical_u32); - self.0 - .iter() - .enumerate() - .map(|(i, x)| base[i].clone() * *x) - .sum() + self.0.iter().enumerate().map(|(i, x)| base[i].clone() * *x).sum() } } diff --git a/zkvm/entrypoint/CHANGELOG.md b/crates/zkvm/entrypoint/CHANGELOG.md similarity index 100% rename from zkvm/entrypoint/CHANGELOG.md rename to crates/zkvm/entrypoint/CHANGELOG.md diff --git a/zkvm/entrypoint/Cargo.toml b/crates/zkvm/entrypoint/Cargo.toml similarity index 100% rename from zkvm/entrypoint/Cargo.toml rename to crates/zkvm/entrypoint/Cargo.toml diff --git a/zkvm/entrypoint/src/heap.rs b/crates/zkvm/entrypoint/src/heap.rs similarity index 100% rename from zkvm/entrypoint/src/heap.rs rename to crates/zkvm/entrypoint/src/heap.rs diff --git a/zkvm/entrypoint/src/lib.rs b/crates/zkvm/entrypoint/src/lib.rs similarity index 100% rename from zkvm/entrypoint/src/lib.rs rename to crates/zkvm/entrypoint/src/lib.rs diff --git a/zkvm/entrypoint/src/libm.rs b/crates/zkvm/entrypoint/src/libm.rs similarity index 100% rename from zkvm/entrypoint/src/libm.rs rename to crates/zkvm/entrypoint/src/libm.rs diff --git a/zkvm/entrypoint/src/memcpy.s b/crates/zkvm/entrypoint/src/memcpy.s similarity index 100% rename from zkvm/entrypoint/src/memcpy.s rename to crates/zkvm/entrypoint/src/memcpy.s diff --git a/zkvm/entrypoint/src/memset.s b/crates/zkvm/entrypoint/src/memset.s similarity index 100% rename from zkvm/entrypoint/src/memset.s rename to crates/zkvm/entrypoint/src/memset.s diff --git a/zkvm/entrypoint/src/syscalls/bigint.rs b/crates/zkvm/entrypoint/src/syscalls/bigint.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/bigint.rs rename to crates/zkvm/entrypoint/src/syscalls/bigint.rs diff --git a/zkvm/entrypoint/src/syscalls/bls12381.rs b/crates/zkvm/entrypoint/src/syscalls/bls12381.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/bls12381.rs rename to crates/zkvm/entrypoint/src/syscalls/bls12381.rs diff --git a/zkvm/entrypoint/src/syscalls/bn254.rs b/crates/zkvm/entrypoint/src/syscalls/bn254.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/bn254.rs rename to crates/zkvm/entrypoint/src/syscalls/bn254.rs diff --git a/zkvm/entrypoint/src/syscalls/ed25519.rs b/crates/zkvm/entrypoint/src/syscalls/ed25519.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/ed25519.rs rename to crates/zkvm/entrypoint/src/syscalls/ed25519.rs diff --git a/crates/zkvm/entrypoint/src/syscalls/fptower.rs b/crates/zkvm/entrypoint/src/syscalls/fptower.rs new file mode 100644 index 0000000000..2fe7b9d67a --- /dev/null +++ b/crates/zkvm/entrypoint/src/syscalls/fptower.rs @@ -0,0 +1,242 @@ +#[cfg(target_os = "zkvm")] +use core::arch::asm; + +/// Fp addition operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp_addmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP_ADD, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Fp subtraction operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp_submod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP_SUB, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Fp multiplication operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp_mulmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP_MUL, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BLS12-381 Fp2 addition operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp2_addmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP2_ADD, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BLS12-381 Fp2 subtraction operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp2_submod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP2_SUB, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BLS12-381 Fp2 multiplication operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bls12381_fp2_mulmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BLS12381_FP2_MUL, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Fp addition operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp_addmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP_ADD, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Fp subtraction operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp_submod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP_SUB, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Fp multiplication operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp_mulmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP_MUL, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BN254 Fp2 addition operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp2_addmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP2_ADD, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BN254 Fp2 subtraction operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp2_submod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP2_SUB, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// BN254 Fp2 multiplication operation. +/// +/// The result is written over the first input. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_bn254_fp2_mulmod(x: *mut u32, y: *const u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::BN254_FP2_MUL, + in("a0") x, + in("a1") y, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/zkvm/entrypoint/src/syscalls/halt.rs b/crates/zkvm/entrypoint/src/syscalls/halt.rs similarity index 89% rename from zkvm/entrypoint/src/syscalls/halt.rs rename to crates/zkvm/entrypoint/src/syscalls/halt.rs index 0673cee42b..da4f7671dc 100644 --- a/zkvm/entrypoint/src/syscalls/halt.rs +++ b/crates/zkvm/entrypoint/src/syscalls/halt.rs @@ -27,9 +27,10 @@ pub extern "C" fn syscall_halt(exit_code: u8) -> ! { .unwrap() .finalize(); - // For each digest word, call COMMIT ecall. In the runtime, this will store the digest words - // into the runtime's execution record's public values digest. In the AIR, it will be used - // to verify that the provided public values digest matches the one computed by the program. + // For each digest word, call COMMIT ecall. In the runtime, this will store the digest + // words into the runtime's execution record's public values digest. In the AIR, it + // will be used to verify that the provided public values digest matches the one + // computed by the program. for i in 0..PV_DIGEST_NUM_WORDS { let word = u32::from_le_bytes(pv_digest_bytes[i * 4..(i + 1) * 4].try_into().unwrap()); asm!("ecall", in("t0") crate::syscalls::COMMIT, in("a0") i, in("a1") word); diff --git a/zkvm/entrypoint/src/syscalls/io.rs b/crates/zkvm/entrypoint/src/syscalls/io.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/io.rs rename to crates/zkvm/entrypoint/src/syscalls/io.rs diff --git a/zkvm/entrypoint/src/syscalls/keccak_permute.rs b/crates/zkvm/entrypoint/src/syscalls/keccak_permute.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/keccak_permute.rs rename to crates/zkvm/entrypoint/src/syscalls/keccak_permute.rs diff --git a/zkvm/entrypoint/src/syscalls/memory.rs b/crates/zkvm/entrypoint/src/syscalls/memory.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/memory.rs rename to crates/zkvm/entrypoint/src/syscalls/memory.rs diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/crates/zkvm/entrypoint/src/syscalls/mod.rs similarity index 69% rename from zkvm/entrypoint/src/syscalls/mod.rs rename to crates/zkvm/entrypoint/src/syscalls/mod.rs index 2e28c51df7..e40728d7ed 100644 --- a/zkvm/entrypoint/src/syscalls/mod.rs +++ b/crates/zkvm/entrypoint/src/syscalls/mod.rs @@ -2,6 +2,7 @@ mod bigint; mod bls12381; mod bn254; mod ed25519; +mod fptower; mod halt; mod io; mod keccak_permute; @@ -19,6 +20,7 @@ pub use bigint::*; pub use bls12381::*; pub use bn254::*; pub use ed25519::*; +pub use fptower::*; pub use halt::*; pub use io::*; pub use keccak_permute::*; @@ -103,3 +105,39 @@ pub const BLS12381_ADD: u32 = 0x00_01_01_1E; /// Executes the `BLS12381_DOUBLE` precompile. pub const BLS12381_DOUBLE: u32 = 0x00_00_01_1F; + +/// Executes the `BLS12381_FP_ADD` precompile. +pub const BLS12381_FP_ADD: u32 = 0x00_01_01_20; + +/// Executes the `BLS12381_FP_SUB` precompile. +pub const BLS12381_FP_SUB: u32 = 0x00_01_01_21; + +/// Executes the `BLS12381_FP_MUL` precompile. +pub const BLS12381_FP_MUL: u32 = 0x00_01_01_22; + +/// Executes the `BLS12381_FP2_ADD` precompile. +pub const BLS12381_FP2_ADD: u32 = 0x00_01_01_23; + +/// Executes the `BLS12381_FP2_SUB` precompile. +pub const BLS12381_FP2_SUB: u32 = 0x00_01_01_24; + +/// Executes the `BLS12381_FP2_MUL` precompile. +pub const BLS12381_FP2_MUL: u32 = 0x00_01_01_25; + +/// Executes the `BN254_FP_ADD` precompile. +pub const BN254_FP_ADD: u32 = 0x00_01_01_26; + +/// Executes the `BN254_FP_SUB` precompile. +pub const BN254_FP_SUB: u32 = 0x00_01_01_27; + +/// Executes the `BN254_FP_MUL` precompile. +pub const BN254_FP_MUL: u32 = 0x00_01_01_28; + +/// Executes the `BN254_FP2_ADD` precompile. +pub const BN254_FP2_ADD: u32 = 0x00_01_01_29; + +/// Executes the `BN254_FP2_SUB` precompile. +pub const BN254_FP2_SUB: u32 = 0x00_01_01_2A; + +/// Executes the `BN254_FP2_MUL` precompile. +pub const BN254_FP2_MUL: u32 = 0x00_01_01_2B; diff --git a/zkvm/entrypoint/src/syscalls/secp256k1.rs b/crates/zkvm/entrypoint/src/syscalls/secp256k1.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/secp256k1.rs rename to crates/zkvm/entrypoint/src/syscalls/secp256k1.rs diff --git a/zkvm/entrypoint/src/syscalls/sha_compress.rs b/crates/zkvm/entrypoint/src/syscalls/sha_compress.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/sha_compress.rs rename to crates/zkvm/entrypoint/src/syscalls/sha_compress.rs diff --git a/zkvm/entrypoint/src/syscalls/sha_extend.rs b/crates/zkvm/entrypoint/src/syscalls/sha_extend.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/sha_extend.rs rename to crates/zkvm/entrypoint/src/syscalls/sha_extend.rs diff --git a/zkvm/entrypoint/src/syscalls/sys.rs b/crates/zkvm/entrypoint/src/syscalls/sys.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/sys.rs rename to crates/zkvm/entrypoint/src/syscalls/sys.rs diff --git a/zkvm/entrypoint/src/syscalls/uint256_mul.rs b/crates/zkvm/entrypoint/src/syscalls/uint256_mul.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/uint256_mul.rs rename to crates/zkvm/entrypoint/src/syscalls/uint256_mul.rs diff --git a/zkvm/entrypoint/src/syscalls/unconstrained.rs b/crates/zkvm/entrypoint/src/syscalls/unconstrained.rs similarity index 100% rename from zkvm/entrypoint/src/syscalls/unconstrained.rs rename to crates/zkvm/entrypoint/src/syscalls/unconstrained.rs diff --git a/zkvm/entrypoint/src/syscalls/verify.rs b/crates/zkvm/entrypoint/src/syscalls/verify.rs similarity index 84% rename from zkvm/entrypoint/src/syscalls/verify.rs rename to crates/zkvm/entrypoint/src/syscalls/verify.rs index 8e1d660955..9346ad792b 100644 --- a/zkvm/entrypoint/src/syscalls/verify.rs +++ b/crates/zkvm/entrypoint/src/syscalls/verify.rs @@ -37,15 +37,11 @@ pub fn syscall_verify_sp1_proof(vk_digest: &[u32; 8], pv_digest: &[u8; 32]) { hash_input.extend_from_slice(deferred_proofs_digest); // Next 8 elements are vkey_digest - let vk_digest_babybear = vk_digest - .iter() - .map(|x| BabyBear::from_canonical_u32(*x)) - .collect::>(); + let vk_digest_babybear = + vk_digest.iter().map(|x| BabyBear::from_canonical_u32(*x)).collect::>(); // Remaining 32 elements are pv_digest converted from u8 to BabyBear - let pv_digest_babybear = pv_digest - .iter() - .map(|b| BabyBear::from_canonical_u8(*b)) - .collect::>(); + let pv_digest_babybear = + pv_digest.iter().map(|b| BabyBear::from_canonical_u8(*b)).collect::>(); *deferred_proofs_digest = hash_deferred_proof( deferred_proofs_digest, diff --git a/zkvm/lib/CHANGELOG.md b/crates/zkvm/lib/CHANGELOG.md similarity index 100% rename from zkvm/lib/CHANGELOG.md rename to crates/zkvm/lib/CHANGELOG.md diff --git a/zkvm/lib/Cargo.toml b/crates/zkvm/lib/Cargo.toml similarity index 79% rename from zkvm/lib/Cargo.toml rename to crates/zkvm/lib/Cargo.toml index 48ea0f008e..3c819bbb62 100644 --- a/zkvm/lib/Cargo.toml +++ b/crates/zkvm/lib/Cargo.toml @@ -14,6 +14,10 @@ anyhow = "1.0.83" bincode = "1.3.3" cfg-if = "1.0.0" serde = { version = "1.0.204", features = ["derive"] } +amcl = { package = "snowbridge-amcl", version = "1.0.2", default-features = false, features = [ + "bls381", +] } +hex = "0.4.3" [features] default = [] diff --git a/zkvm/lib/src/bls12381.rs b/crates/zkvm/lib/src/bls12381.rs similarity index 67% rename from zkvm/lib/src/bls12381.rs rename to crates/zkvm/lib/src/bls12381.rs index 4250fdaf1a..4bf0a4d3e9 100644 --- a/zkvm/lib/src/bls12381.rs +++ b/crates/zkvm/lib/src/bls12381.rs @@ -1,5 +1,8 @@ -use crate::utils::AffinePoint; -use crate::{syscall_bls12381_add, syscall_bls12381_double}; +use std::io::ErrorKind; + +use crate::{ + syscall_bls12381_add, syscall_bls12381_decompress, syscall_bls12381_double, utils::AffinePoint, +}; /// The number of limbs in [Bls12381AffinePoint]. pub const N: usize = 24; @@ -47,3 +50,17 @@ impl AffinePoint for Bls12381AffinePoint { } } } + +/// Decompresses a compressed public key using bls12381_decompress precompile. +pub fn decompress_pubkey(compressed_key: &[u8; 48]) -> Result<[u8; 96], ErrorKind> { + let mut decompressed_key = [0u8; 96]; + decompressed_key[..48].copy_from_slice(compressed_key); + + let sign_bit = ((decompressed_key[0] & 0b_0010_0000) >> 5) == 1; + decompressed_key[0] &= 0b_0001_1111; + unsafe { + syscall_bls12381_decompress(&mut decompressed_key, sign_bit); + } + + Ok(decompressed_key) +} diff --git a/zkvm/lib/src/bn254.rs b/crates/zkvm/lib/src/bn254.rs similarity index 88% rename from zkvm/lib/src/bn254.rs rename to crates/zkvm/lib/src/bn254.rs index 011c614347..f3635f3f63 100644 --- a/zkvm/lib/src/bn254.rs +++ b/crates/zkvm/lib/src/bn254.rs @@ -1,10 +1,9 @@ -use crate::utils::AffinePoint; -use crate::{syscall_bn254_add, syscall_bn254_double}; +use crate::{syscall_bn254_add, syscall_bn254_double, utils::AffinePoint}; /// The number of limbs in [Bn254AffinePoint]. pub const N: usize = 16; -/// An affine point on the BLS12-381 curve. +/// An affine point on the Bn254 curve. #[derive(Copy, Clone)] #[repr(align(4))] pub struct Bn254AffinePoint(pub [u32; N]); diff --git a/zkvm/lib/src/ed25519.rs b/crates/zkvm/lib/src/ed25519.rs similarity index 95% rename from zkvm/lib/src/ed25519.rs rename to crates/zkvm/lib/src/ed25519.rs index f801ee310a..3eea834eb4 100644 --- a/zkvm/lib/src/ed25519.rs +++ b/crates/zkvm/lib/src/ed25519.rs @@ -1,5 +1,4 @@ -use crate::syscall_ed_add; -use crate::utils::AffinePoint; +use crate::{syscall_ed_add, utils::AffinePoint}; /// The number of limbs in [Ed25519AffinePoint]. pub const N: usize = 16; diff --git a/zkvm/lib/src/io.rs b/crates/zkvm/lib/src/io.rs similarity index 92% rename from zkvm/lib/src/io.rs rename to crates/zkvm/lib/src/io.rs index 3845981f38..48faad5f14 100644 --- a/zkvm/lib/src/io.rs +++ b/crates/zkvm/lib/src/io.rs @@ -1,11 +1,10 @@ #![allow(unused_unsafe)] -use crate::syscall_write; -use crate::{syscall_hint_len, syscall_hint_read}; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::alloc::Layout; -use std::io::Result; -use std::io::Write; +use crate::{syscall_hint_len, syscall_hint_read, syscall_write}; +use serde::{de::DeserializeOwned, Serialize}; +use std::{ + alloc::Layout, + io::{Result, Write}, +}; /// The file descriptor for public values. pub const FD_PUBLIC_VALUES: u32 = 3; @@ -106,9 +105,7 @@ pub fn read() -> T { /// sp1_zkvm::io::commit(&data); /// ``` pub fn commit(value: &T) { - let writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; + let writer = SyscallWriter { fd: FD_PUBLIC_VALUES }; bincode::serialize_into(writer, value).expect("serialization failed"); } @@ -120,9 +117,7 @@ pub fn commit(value: &T) { /// sp1_zkvm::io::commit_slice(&data); /// ``` pub fn commit_slice(buf: &[u8]) { - let mut my_writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; + let mut my_writer = SyscallWriter { fd: FD_PUBLIC_VALUES }; my_writer.write_all(buf).unwrap(); } diff --git a/zkvm/lib/src/lib.rs b/crates/zkvm/lib/src/lib.rs similarity index 66% rename from zkvm/lib/src/lib.rs rename to crates/zkvm/lib/src/lib.rs index 3b3ef25f8e..f849859a8b 100644 --- a/zkvm/lib/src/lib.rs +++ b/crates/zkvm/lib/src/lib.rs @@ -69,7 +69,7 @@ extern "C" { pub fn syscall_exit_unconstrained(); /// Defers the verification of a valid SP1 zkVM proof. - pub fn syscall_verify_sp1_proof(vkey: &[u32; 8], pv_digest: &[u8; 32]); + pub fn syscall_verify_sp1_proof(vk_digest: &[u32; 8], pv_digest: &[u8; 32]); /// Returns the length of the next element in the hint stream. pub fn syscall_hint_len() -> usize; @@ -91,4 +91,41 @@ extern "C" { y: *const [u32; 8], modulus: *const [u32; 8], ); + + /// Executes a BLS12-381 field addition on the given inputs. + pub fn syscall_bls12381_fp_addmod(p: *mut u32, q: *const u32); + + /// Executes a BLS12-381 field subtraction on the given inputs. + pub fn syscall_bls12381_fp_submod(p: *mut u32, q: *const u32); + + /// Executes a BLS12-381 field multiplication on the given inputs. + pub fn syscall_bls12381_fp_mulmod(p: *mut u32, q: *const u32); + + /// Executes a BLS12-381 Fp2 addition on the given inputs. + pub fn syscall_bls12381_fp2_addmod(p: *mut u32, q: *const u32); + + /// Executes a BLS12-381 Fp2 subtraction on the given inputs. + pub fn syscall_bls12381_fp2_submod(p: *mut u32, q: *const u32); + + /// Executes a BLS12-381 Fp2 multiplication on the given inputs. + pub fn syscall_bls12381_fp2_mulmod(p: *mut u32, q: *const u32); + + /// Executes a BN254 field addition on the given inputs. + pub fn syscall_bn254_fp_addmod(p: *mut u32, q: *const u32); + + /// Executes a BN254 field subtraction on the given inputs. + pub fn syscall_bn254_fp_submod(p: *mut u32, q: *const u32); + + /// Executes a BN254 field multiplication on the given inputs. + pub fn syscall_bn254_fp_mulmod(p: *mut u32, q: *const u32); + + /// Executes a BN254 Fp2 addition on the given inputs. + pub fn syscall_bn254_fp2_addmod(p: *mut u32, q: *const u32); + + /// Executes a BN254 Fp2 subtraction on the given inputs. + pub fn syscall_bn254_fp2_submod(p: *mut u32, q: *const u32); + + /// Executes a BN254 Fp2 multiplication on the given inputs. + pub fn syscall_bn254_fp2_mulmod(p: *mut u32, q: *const u32); + } diff --git a/zkvm/lib/src/secp256k1.rs b/crates/zkvm/lib/src/secp256k1.rs similarity index 92% rename from zkvm/lib/src/secp256k1.rs rename to crates/zkvm/lib/src/secp256k1.rs index 6624bed56d..9106bd2ac3 100644 --- a/zkvm/lib/src/secp256k1.rs +++ b/crates/zkvm/lib/src/secp256k1.rs @@ -1,5 +1,4 @@ -use crate::utils::AffinePoint; -use crate::{syscall_secp256k1_add, syscall_secp256k1_double}; +use crate::{syscall_secp256k1_add, syscall_secp256k1_double, utils::AffinePoint}; /// The number of limbs in [Secp256k1AffinePoint]. pub const N: usize = 16; diff --git a/zkvm/lib/src/unconstrained.rs b/crates/zkvm/lib/src/unconstrained.rs similarity index 100% rename from zkvm/lib/src/unconstrained.rs rename to crates/zkvm/lib/src/unconstrained.rs diff --git a/zkvm/lib/src/utils.rs b/crates/zkvm/lib/src/utils.rs similarity index 97% rename from zkvm/lib/src/utils.rs rename to crates/zkvm/lib/src/utils.rs index 16d432a795..b0b3193187 100644 --- a/zkvm/lib/src/utils.rs +++ b/crates/zkvm/lib/src/utils.rs @@ -120,10 +120,7 @@ pub enum MulAssignError { /// Converts a slice of words to a byte array in little endian. pub fn words_to_bytes_le(words: &[u32]) -> Vec { - words - .iter() - .flat_map(|word| word.to_le_bytes().to_vec()) - .collect::>() + words.iter().flat_map(|word| word.to_le_bytes().to_vec()).collect::>() } /// Converts a byte array in little endian to a slice of words. diff --git a/crates/zkvm/lib/src/verify.rs b/crates/zkvm/lib/src/verify.rs new file mode 100644 index 0000000000..5bff852fed --- /dev/null +++ b/crates/zkvm/lib/src/verify.rs @@ -0,0 +1,11 @@ +use crate::syscall_verify_sp1_proof; + +/// Verifies the next proof in the proof input stream given a verification key digest and public +/// values digest. If the proof is invalid, the function will panic. +/// +/// Enable this function by adding the `verify` feature to both the `sp1-lib` AND `sp1-zkvm` crates. +pub fn verify_sp1_proof(vk_digest: &[u32; 8], pv_digest: &[u8; 32]) { + unsafe { + syscall_verify_sp1_proof(vk_digest, pv_digest); + } +} diff --git a/eval/Cargo.toml b/eval/Cargo.toml deleted file mode 100644 index 3cf9b539f9..0000000000 --- a/eval/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "sp1-eval" -version = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -repository = { workspace = true } -keywords = { workspace = true } -categories = { workspace = true } -publish = false - -[dependencies] -sp1-core = { workspace = true } -sp1-prover = { workspace = true } - -clap = { version = "4.5.9", features = ["derive"] } -csv = "1.3.0" -serde = "1.0.204" diff --git a/eval/src/main.rs b/eval/src/main.rs deleted file mode 100644 index 5721bdba82..0000000000 --- a/eval/src/main.rs +++ /dev/null @@ -1,227 +0,0 @@ -use clap::{command, Parser}; -use csv::WriterBuilder; -use serde::Serialize; -use sp1_core::runtime::{Program, Runtime}; -use sp1_core::stark::CpuProver; -use sp1_core::utils::{ - prove_simple, BabyBearBlake3, BabyBearKeccak, BabyBearPoseidon2, SP1CoreOpts, -}; -use sp1_prover::utils::get_cycles; -use sp1_prover::SP1Stdin; -use std::fmt; -use std::fs::OpenOptions; -use std::io; -use std::{fs, time::Instant}; - -/// An identifier used to select the hash function to evaluate. -#[derive(clap::ValueEnum, Clone)] -enum HashFnId { - Sha256, - Poseidon, - Blake3, - Keccak256, -} - -impl fmt::Display for HashFnId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let hash_fn_str = match self { - HashFnId::Sha256 => "sha-256", - HashFnId::Poseidon => "poseidon", - HashFnId::Blake3 => "blake3", - HashFnId::Keccak256 => "keccak256", - }; - write!(f, "{}", hash_fn_str) - } -} - -/// The performance report of a zkVM on a program. -#[derive(Debug, Serialize)] -pub struct PerformanceReport { - /// The program that is being evaluated. - pub program: String, - - /// The hash function that is being evaluated. - pub hashfn: String, - - /// The shard size that is being evaluated. - pub shard_size: u64, - - /// The reported number of cycles. - pub cycles: u64, - - /// The reported speed in cycles per second. - pub speed: f64, - - /// The reported duration of the execution in seconds. - pub execution_duration: f64, - - /// The reported duration of the prover in seconds. - pub prove_duration: f64, - - /// The reported duration of the verifier in seconds. - pub verify_duration: f64, -} - -#[derive(Parser, Clone)] -#[command(about = "Evaluate the performance of a zkVM on a program.")] -struct EvalArgs { - #[arg(long)] - pub program: String, - - #[arg(long)] - pub hashfn: HashFnId, - - #[arg(long)] - pub shard_size: u64, - - #[arg(long)] - pub benchmark_path: String, - - #[arg(long)] - pub elf_path: String, - - #[arg(long, default_value_t = 1)] - pub runs: usize, -} - -fn main() { - let args = EvalArgs::parse(); - - // Load the program. - let elf_path = &args.elf_path; - let elf = fs::read(elf_path).expect("Failed to read ELF file"); - let cycles = get_cycles(&elf, &SP1Stdin::new()); - - // Initialize total duration counters. - let mut total_execution_duration = 0f64; - let mut total_prove_duration = 0f64; - let mut total_verify_duration = 0f64; - - // Perform runs. - let program = Program::from(&elf); - for _ in 0..args.runs { - let elf = fs::read(elf_path).expect("Failed to read ELF file"); - let (execution_duration, prove_duration, verify_duration) = - run_evaluation(&args.hashfn, &program, &elf); - - // Accumulate durations. - total_execution_duration += execution_duration; - total_prove_duration += prove_duration; - total_verify_duration += verify_duration; - } - - // Calculate average durations. - let avg_execution_duration = total_execution_duration / args.runs as f64; - let avg_prove_duration = total_prove_duration / args.runs as f64; - let avg_verify_duration = total_verify_duration / args.runs as f64; - - let report = PerformanceReport { - program: args.program, - hashfn: args.hashfn.to_string(), - shard_size: args.shard_size, - cycles, - speed: cycles as f64 / avg_prove_duration, - execution_duration: avg_execution_duration, - prove_duration: avg_prove_duration, - verify_duration: avg_verify_duration, - }; - - // Write the report. - if let Err(e) = write_report(report, &args.benchmark_path) { - eprintln!("Failed to write report: {}", e); - } -} - -fn run_evaluation(hashfn: &HashFnId, program: &Program, _elf: &[u8]) -> (f64, f64, f64) { - // Note: While these benchmarks are useful for core proving, they are not useful for recursion - // or end to end proving as we only support Poseidon for now. - match hashfn { - HashFnId::Blake3 => { - let opts = SP1CoreOpts::default(); - let mut runtime = Runtime::new(program.clone(), opts); - let execution_start = Instant::now(); - runtime.run().unwrap(); - let execution_duration = execution_start.elapsed().as_secs_f64(); - - let config = BabyBearBlake3::new(); - let prove_start = Instant::now(); - let _proof = prove_simple::<_, CpuProver<_, _>>(config.clone(), runtime); - let prove_duration = prove_start.elapsed().as_secs_f64(); - - let verify_start = Instant::now(); - // SP1ProverImpl::verify_with_config(elf, &proof, config).unwrap(); - let verify_duration = verify_start.elapsed().as_secs_f64(); - - (execution_duration, prove_duration, verify_duration) - } - HashFnId::Poseidon => { - let opts = SP1CoreOpts::default(); - let mut runtime = Runtime::new(program.clone(), opts); - let execution_start = Instant::now(); - runtime.run().unwrap(); - let execution_duration = execution_start.elapsed().as_secs_f64(); - - let config = BabyBearPoseidon2::new(); - let prove_start = Instant::now(); - let _proof = prove_simple::<_, CpuProver<_, _>>(config.clone(), runtime); - let prove_duration = prove_start.elapsed().as_secs_f64(); - - let verify_start = Instant::now(); - // SP1ProverImpl::verify_with_config(elf, &proof, config).unwrap(); - let verify_duration = verify_start.elapsed().as_secs_f64(); - - (execution_duration, prove_duration, verify_duration) - } - HashFnId::Keccak256 => { - let opts = SP1CoreOpts::default(); - let mut runtime = Runtime::new(program.clone(), opts); - let execution_start = Instant::now(); - runtime.run().unwrap(); - let execution_duration = execution_start.elapsed().as_secs_f64(); - - let config = BabyBearKeccak::new(); - let prove_start = Instant::now(); - let _proof = prove_simple::<_, CpuProver<_, _>>(config.clone(), runtime); - let prove_duration = prove_start.elapsed().as_secs_f64(); - - let verify_start = Instant::now(); - // SP1ProverImpl::verify_with_config(elf, &proof, config).unwrap(); - let verify_duration = verify_start.elapsed().as_secs_f64(); - - (execution_duration, prove_duration, verify_duration) - } - _ => panic!("Unsupported hash function"), - } -} - -fn write_report(report: PerformanceReport, benchmark_path: &str) -> io::Result<()> { - // Check if the file exists and is empty to determine if the header needs to be written. - let write_header = fs::metadata(benchmark_path).map_or(true, |meta| meta.len() == 0); - - let file = OpenOptions::new() - .create(true) - .append(true) - .open(benchmark_path)?; - - let mut writer = WriterBuilder::new().has_headers(false).from_writer(file); - - // Manually write the header if needed. - if write_header { - writer.write_record([ - "program", - "hashfn", - "shard_size", - "cycles", - "speed", - "execution_duration", - "prove_duration", - "verify_duration", - ])?; - } - - // Serialize the report to the CSV file. - writer.serialize(report)?; - writer.flush()?; - - Ok(()) -} diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 7736faa6c4..03ce396330 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -54,7 +54,7 @@ name = "aggregation-script" version = "1.1.0" dependencies = [ "hex", - "sp1-helper", + "sp1-build", "sp1-sdk", "tracing", ] @@ -68,7 +68,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" dependencies = [ "arrayvec", "bytes", @@ -129,7 +129,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -141,11 +141,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.3.0", + "indexmap 2.4.0", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", "syn-solidity", "tiny-keccak", ] @@ -161,7 +161,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", "syn-solidity", ] @@ -388,9 +388,9 @@ checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" @@ -400,7 +400,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -428,7 +428,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -570,9 +570,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", - "syn 2.0.72", + "syn 2.0.75", "which", ] @@ -637,9 +637,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec", @@ -704,9 +704,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.16.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" [[package]] name = "byteorder" @@ -725,9 +725,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -757,12 +757,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -780,11 +781,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chess-script" version = "1.1.0" dependencies = [ - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -824,9 +831,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -834,9 +841,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -853,7 +860,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -988,15 +995,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -1073,6 +1080,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -1096,7 +1113,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1116,7 +1133,7 @@ dependencies = [ name = "cycle-tracking-script" version = "1.1.0" dependencies = [ - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -1141,7 +1158,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1152,7 +1169,85 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.75", +] + +[[package]] +name = "dashu" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b3e5ac1e23ff1995ef05b912e2b012a8784506987a2651552db2c73fb3d7e0" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-macros", + "dashu-ratio", + "rustversion", +] + +[[package]] +name = "dashu-base" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b80bf6b85aa68c58ffea2ddb040109943049ce3fbdf4385d0380aef08ef289" + +[[package]] +name = "dashu-float" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85078445a8dbd2e1bd21f04a816f352db8d333643f0c9b78ca7c3d1df71063e7" +dependencies = [ + "dashu-base", + "dashu-int", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-int" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee99d08031ca34a4d044efbbb21dff9b8c54bb9d8c82a189187c0651ffdb9fbf" +dependencies = [ + "cfg-if", + "dashu-base", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93381c3ef6366766f6e9ed9cf09e4ef9dec69499baf04f0c60e70d653cf0ab10" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-ratio", + "paste", + "proc-macro2", + "quote", + "rustversion", +] + +[[package]] +name = "dashu-ratio" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33b04dd7ce1ccf8a02a69d3419e354f2bbfdf4eb911a0b7465487248764c9" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "num-modular", + "num-order", + "rustversion", ] [[package]] @@ -1207,7 +1302,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1260,9 +1355,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ecdsa" @@ -1338,6 +1433,12 @@ 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 = "encode_unicode" version = "0.3.6" @@ -1519,7 +1620,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.72", + "syn 2.0.75", "toml", "walkdir", ] @@ -1537,7 +1638,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -1563,7 +1664,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.72", + "syn 2.0.75", "tempfile", "thiserror", "tiny-keccak", @@ -1730,7 +1831,7 @@ version = "1.1.0" dependencies = [ "itertools 0.12.1", "sha2 0.10.8", - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -1857,7 +1958,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -2019,7 +2120,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -2028,9 +2129,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -2038,7 +2139,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -2243,7 +2344,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -2304,9 +2405,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -2418,9 +2519,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -2463,7 +2564,7 @@ name = "io-script" version = "1.1.0" dependencies = [ "serde", - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -2530,9 +2631,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -2544,7 +2645,7 @@ dependencies = [ "lib", "serde", "serde_json", - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -2601,9 +2702,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -2633,9 +2734,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libgit2-sys" @@ -2677,9 +2778,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" dependencies = [ "cc", "libc", @@ -2759,9 +2860,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -2786,6 +2887,18 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2896,7 +3009,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -2919,6 +3032,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2989,7 +3117,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -3009,9 +3137,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -3082,7 +3210,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -3484,8 +3612,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" name = "patch-testing-script" version = "1.1.0" dependencies = [ - "sp1-core", - "sp1-helper", + "sp1-build", + "sp1-core-executor", + "sp1-core-machine", "sp1-sdk", ] @@ -3570,7 +3699,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -3631,12 +3760,13 @@ checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "20ee10b999a00ca189ac2cb99f5db1ca71fb7371e3d5f493b879ca95d2a67220" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -3648,11 +3778,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy 0.6.6", + "zerocopy", ] [[package]] @@ -3662,7 +3792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -3771,7 +3901,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -3800,16 +3930,17 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", + "socket2", "thiserror", "tokio", "tracing", @@ -3817,14 +3948,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" dependencies = [ "bytes", "rand", "ring 0.17.8", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "slab", "thiserror", @@ -3841,6 +3972,7 @@ dependencies = [ "libc", "once_cell", "socket2", + "tracing", "windows-sys 0.52.0", ] @@ -3938,9 +4070,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -3983,7 +4115,7 @@ dependencies = [ name = "regex-script" version = "1.1.0" dependencies = [ - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -4028,7 +4160,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", "tower-service", @@ -4036,21 +4168,21 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "http-body-util", @@ -4068,13 +4200,13 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.1", - "system-configuration", + "system-configuration 0.6.0", "tokio", "tokio-native-tls", "tokio-rustls", @@ -4086,19 +4218,19 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots", - "winreg 0.52.0", + "windows-registry", ] [[package]] name = "reqwest-middleware" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39346a33ddfe6be00cbc17a34ce996818b97b230b87229f10114693becca1268" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" dependencies = [ "anyhow", "async-trait", "http 1.1.0", - "reqwest 0.12.5", + "reqwest 0.12.7", "serde", "thiserror", "tower-service", @@ -4211,7 +4343,7 @@ name = "rsa-script" version = "1.1.0" dependencies = [ "rsa", - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -4257,6 +4389,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -4319,9 +4457,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -4329,9 +4467,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -4412,9 +4550,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.6" +version = "2.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ccfb12511cdb770157ace92d7dda771e498445b78f9886e8cdbc5140a4eced" +checksum = "aeb7ac86243095b70a7920639507b71d51a63390d1ba26c4f60a552fbb914a37" dependencies = [ "sdd", ] @@ -4448,9 +4586,9 @@ dependencies = [ [[package]] name = "sdd" -version = "2.1.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177258b64c0faaa9ffd3c65cd3262c2bc7e2588dbbd9c1641d0346145c1bbda8" +checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" [[package]] name = "sec1" @@ -4530,9 +4668,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -4558,20 +4696,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", "memchr", @@ -4597,7 +4735,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -4631,7 +4769,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_derive", "serde_json", @@ -4648,7 +4786,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -4673,7 +4811,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -4712,9 +4850,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" dependencies = [ "cc", "cfg-if", @@ -4809,17 +4947,52 @@ dependencies = [ [[package]] name = "sp1-build" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "anyhow", "cargo_metadata", + "chrono", "clap", "dirs", ] [[package]] -name = "sp1-core" -version = "1.1.0" +name = "sp1-core-executor" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "bytemuck", + "elf", + "eyre", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "nohash-hasher", + "num", + "p3-field", + "p3-keccak-air", + "p3-maybe-rayon", + "rand", + "rrs-succinct", + "serde", + "serde_with", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "strum", + "strum_macros", + "thiserror", + "tiny-keccak", + "tracing", + "typenum", +] + +[[package]] +name = "sp1-core-machine" +version = "1.2.0-rc1" dependencies = [ "anyhow", "arrayref", @@ -4864,8 +5037,11 @@ dependencies = [ "serde_with", "size", "snowbridge-amcl", + "sp1-core-executor", + "sp1-curves", "sp1-derive", "sp1-primitives", + "sp1-stark", "static_assertions", "strum", "strum_macros", @@ -4879,26 +5055,55 @@ dependencies = [ ] [[package]] -name = "sp1-derive" -version = "1.1.0" +name = "sp1-cuda" +version = "1.2.0-rc1" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bincode", + "ctrlc", + "prost", + "prost-types", + "serde", + "serde_json", + "sp1-core-machine", + "sp1-prover", + "sp1-stark", + "tokio", + "tracing", + "tracing-subscriber", + "twirp-rs", ] [[package]] -name = "sp1-helper" -version = "1.1.0" +name = "sp1-curves" +version = "1.2.0-rc1" dependencies = [ - "cargo_metadata", - "chrono", - "sp1-build", + "curve25519-dalek", + "dashu", + "elliptic-curve", + "generic-array 1.1.0", + "itertools 0.13.0", + "k256", + "num", + "p3-field", + "serde", + "snowbridge-amcl", + "sp1-primitives", + "sp1-stark", + "typenum", +] + +[[package]] +name = "sp1-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "sp1-primitives" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "itertools 0.13.0", "lazy_static", @@ -4910,7 +5115,7 @@ dependencies = [ [[package]] name = "sp1-prover" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", @@ -4930,13 +5135,15 @@ dependencies = [ "serde", "serde_json", "serial_test", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-circuit", "sp1-recursion-compiler", "sp1-recursion-core", "sp1-recursion-gnark-ffi", "sp1-recursion-program", + "sp1-stark", "subtle-encoding", "tempfile", "thiserror", @@ -4946,7 +5153,7 @@ dependencies = [ [[package]] name = "sp1-recursion-circuit" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "bincode", "itertools 0.13.0", @@ -4959,16 +5166,17 @@ dependencies = [ "p3-matrix", "p3-util", "serde", - "sp1-core", + "sp1-core-machine", "sp1-recursion-compiler", "sp1-recursion-core", "sp1-recursion-derive", "sp1-recursion-program", + "sp1-stark", ] [[package]] name = "sp1-recursion-compiler" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "backtrace", "itertools 0.13.0", @@ -4982,17 +5190,21 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "p3-util", + "rayon", "serde", - "sp1-core", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-core", + "sp1-recursion-core-v2", "sp1-recursion-derive", + "sp1-stark", "tracing", + "vec_map", ] [[package]] name = "sp1-recursion-core" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "arrayref", "backtrace", @@ -5016,17 +5228,58 @@ dependencies = [ "p3-util", "serde", "serde_with", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-derive", "sp1-primitives", + "sp1-stark", "static_assertions", "tracing", "zkhash", ] +[[package]] +name = "sp1-recursion-core-v2" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-recursion-core", + "sp1-stark", + "static_assertions", + "thiserror", + "tracing", + "vec_map", + "zkhash", +] + [[package]] name = "sp1-recursion-derive" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "proc-macro2", "quote", @@ -5035,7 +5288,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", @@ -5052,14 +5305,15 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "sp1-core", + "sp1-core-machine", "sp1-recursion-compiler", + "sp1-stark", "tempfile", ] [[package]] name = "sp1-recursion-program" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "itertools 0.13.0", "p3-air", @@ -5077,17 +5331,19 @@ dependencies = [ "p3-util", "rand", "serde", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", "sp1-primitives", "sp1-recursion-compiler", "sp1-recursion-core", + "sp1-stark", "stacker", "tracing", ] [[package]] name = "sp1-sdk" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "alloy-sol-types", "anyhow", @@ -5109,13 +5365,16 @@ dependencies = [ "p3-fri", "p3-matrix", "prost", - "reqwest 0.12.5", + "reqwest 0.12.7", "reqwest-middleware", "serde", "serde_json", "sha2 0.10.8", - "sp1-core", + "sp1-core-executor", + "sp1-core-machine", + "sp1-cuda", "sp1-prover", + "sp1-stark", "strum", "strum_macros", "sysinfo", @@ -5127,6 +5386,34 @@ dependencies = [ "vergen", ] +[[package]] +name = "sp1-stark" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rayon-scan", + "serde", + "sp1-derive", + "sp1-primitives", + "tracing", +] + [[package]] name = "spin" version = "0.5.2" @@ -5163,7 +5450,7 @@ dependencies = [ name = "ssz-withdrawals-script" version = "1.1.0" dependencies = [ - "sp1-helper", + "sp1-build", "sp1-sdk", ] @@ -5211,7 +5498,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -5248,9 +5535,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -5266,7 +5553,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -5280,6 +5567,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "sysinfo" @@ -5304,7 +5594,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -5317,6 +5618,16 @@ dependencies = [ "libc", ] +[[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" @@ -5325,15 +5636,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5407,8 +5718,8 @@ dependencies = [ "serde_cbor", "serde_json", "sha2 0.10.8", - "sp1-core", - "sp1-helper", + "sp1-build", + "sp1-core-machine", "sp1-sdk", "tendermint", "tendermint-light-client-verifier", @@ -5432,7 +5743,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -5504,9 +5815,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", @@ -5528,7 +5839,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -5592,7 +5903,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "toml_datetime", "winnow 0.5.40", ] @@ -5603,7 +5914,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "toml_datetime", "winnow 0.5.40", ] @@ -5614,7 +5925,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -5639,15 +5950,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -5669,7 +5980,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -5754,7 +6065,7 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "prost", - "reqwest 0.12.5", + "reqwest 0.12.7", "serde", "serde_json", "thiserror", @@ -5822,9 +6133,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "untrusted" @@ -5877,6 +6188,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "vergen" version = "8.3.2" @@ -5932,34 +6249,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -5969,9 +6287,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5979,22 +6297,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-streams" @@ -6011,9 +6329,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -6100,6 +6418,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6276,16 +6624,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -6314,34 +6652,14 @@ dependencies = [ "tap", ] -[[package]] -name = "zerocopy" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" -dependencies = [ - "byteorder", - "zerocopy-derive 0.6.6", -] - [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy-derive" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", + "byteorder", + "zerocopy-derive", ] [[package]] @@ -6352,7 +6670,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] @@ -6372,7 +6690,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.75", ] [[package]] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 823e75a80f..83f568a4b6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -21,20 +21,21 @@ version = "1.1.0" edition = "2021" [workspace.dependencies] -sp1-build = { path = "../build" } -sp1-derive = { path = "../derive" } -sp1-core = { path = "../core" } -sp1-cli = { path = "../cli", default-features = false } -sp1-eval = { path = "../eval", default-features = false } -sp1-helper = { path = "../helper", default-features = false } -sp1-primitives = { path = "../primitives" } -sp1-prover = { path = "../prover" } -sp1-recursion-compiler = { path = "../recursion/compiler" } -sp1-recursion-core = { path = "../recursion/core", default-features = false } -sp1-recursion-derive = { path = "../recursion/derive", default-features = false } -sp1-recursion-gnark-ffi = { path = "../recursion/gnark-ffi", default-features = false } -sp1-recursion-program = { path = "../recursion/program", default-features = false } -sp1-recursion-circuit = { path = "../recursion/circuit", default-features = false } -sp1-sdk = { path = "../sdk" } -sp1-lib = { path = "../zkvm/lib", default-features = false } -sp1-zkvm = { path = "../zkvm/entrypoint", default-features = false } +sp1-build = { path = "../crates/build" } +sp1-derive = { path = "../crates/derive" } +sp1-core-executor = { path = "../crates/core/executor" } +sp1-core-machine = { path = "../crates/core/machine" } +sp1-cli = { path = "../crates/cli", default-features = false } +sp1-eval = { path = "../crates/eval", default-features = false } +sp1-helper = { path = "../crates/helper", default-features = false } +sp1-primitives = { path = "../crates/primitives" } +sp1-prover = { path = "../crates/prover" } +sp1-recursion-compiler = { path = "../crates/recursion/compiler" } +sp1-recursion-core = { path = "../crates/recursion/core", default-features = false } +sp1-recursion-derive = { path = "../crates/recursion/derive", default-features = false } +sp1-recursion-gnark-ffi = { path = "../crates/recursion/gnark-ffi", default-features = false } +sp1-recursion-program = { path = "../crates/recursion/program", default-features = false } +sp1-recursion-circuit = { path = "../crates/recursion/circuit", default-features = false } +sp1-sdk = { path = "../crates/sdk" } +sp1-lib = { path = "../crates/zkvm/lib", default-features = false } +sp1-zkvm = { path = "../crates/zkvm/entrypoint", default-features = false } diff --git a/examples/aggregation/program/Cargo.lock b/examples/aggregation/program/Cargo.lock index 89e855237e..57b07bc689 100644 --- a/examples/aggregation/program/Cargo.lock +++ b/examples/aggregation/program/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.3.0" @@ -41,6 +47,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -66,6 +78,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "digest" version = "0.10.7" @@ -82,6 +105,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "gcd" version = "2.3.0" @@ -109,12 +138,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itertools" version = "0.12.1" @@ -151,6 +207,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "num-bigint" version = "0.4.5" @@ -296,6 +358,30 @@ dependencies = [ "serde", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -308,6 +394,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.85" @@ -356,6 +451,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -373,7 +492,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] [[package]] @@ -386,19 +505,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-primitives" -version = "1.1.0" +version = "1.1.1" dependencies = [ "itertools 0.13.0", "lazy_static", @@ -410,7 +541,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -427,6 +558,17 @@ dependencies = [ "sp1-primitives", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.66" @@ -438,6 +580,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -457,7 +616,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] [[package]] @@ -492,3 +651,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/aggregation/program/Cargo.toml b/examples/aggregation/program/Cargo.toml index b9ff04be6e..716ee823b7 100644 --- a/examples/aggregation/program/Cargo.toml +++ b/examples/aggregation/program/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] hex = "0.4.3" sha2 = "0.10.8" -sp1-zkvm = { path = "../../../zkvm/entrypoint", features = ["verify"] } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint", features = ["verify"] } [patch.crates-io] sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes.git", package = "sha2", branch = "patch-v0.10.8" } diff --git a/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf b/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf index 25579c2dd3..c572a1a353 100755 Binary files a/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf and b/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/aggregation/script/Cargo.toml b/examples/aggregation/script/Cargo.toml index 4df959459c..7b3e3e3aee 100644 --- a/examples/aggregation/script/Cargo.toml +++ b/examples/aggregation/script/Cargo.toml @@ -10,4 +10,4 @@ sp1-sdk = { workspace = true } tracing = "0.1.40" [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/aggregation/script/build.rs b/examples/aggregation/script/build.rs index 5afa1d66bb..e2034489b2 100644 --- a/examples/aggregation/script/build.rs +++ b/examples/aggregation/script/build.rs @@ -1,6 +1,6 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); - sp1_helper::build_program(&format!( + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!( "{}/../../fibonacci/program", env!("CARGO_MANIFEST_DIR") )); diff --git a/examples/bls12381/program/Cargo.lock b/examples/bls12381/program/Cargo.lock new file mode 100644 index 0000000000..9cb3e8b533 --- /dev/null +++ b/examples/bls12381/program/Cargo.lock @@ -0,0 +1,671 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12381" +version = "1.1.0" +dependencies = [ + "bls12_381", + "ff", + "group", + "num", + "rand", + "serde_yaml", + "sp1-zkvm", +] + +[[package]] +name = "bls12_381" +version = "0.8.0" +source = "git+https://github.com/sp1-patches/bls12_381?branch=patch-v0.8.0#0c37e2976d3c55a5be5e5dd17e5aba444711ecd7" +dependencies = [ + "cfg-if", + "ff", + "group", + "pairing", + "rand_core", + "sp1-lib 1.1.1 (git+https://github.com/succinctlabs/sp1?branch=dev)", + "subtle", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "hex", + "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +source = "git+https://github.com/succinctlabs/sp1?branch=dev#d3a73a9fc33351df68cf1f12625cd48b7415c77f" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "hex", + "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib 1.1.1", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] diff --git a/examples/bls12381/program/Cargo.toml b/examples/bls12381/program/Cargo.toml new file mode 100644 index 0000000000..75de7ceeea --- /dev/null +++ b/examples/bls12381/program/Cargo.toml @@ -0,0 +1,15 @@ +[workspace] +[package] +name = "bls12381" +version = "1.1.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } +num = { version = "0.4.1", default-features = false } +serde_yaml = "0.9.34" +bls12_381 = { git = "https://github.com/sp1-patches/bls12_381", branch = "patch-v0.8.0" } +ff = "0.13.0" +rand = "0.8.5" +group = "0.13.0" diff --git a/examples/bls12381/program/elf/riscv32im-succinct-zkvm-elf b/examples/bls12381/program/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..9b86166a26 Binary files /dev/null and b/examples/bls12381/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/bls12381/program/src/main.rs b/examples/bls12381/program/src/main.rs new file mode 100644 index 0000000000..91f9a114f8 --- /dev/null +++ b/examples/bls12381/program/src/main.rs @@ -0,0 +1,106 @@ +#![no_main] + +use bls12_381::{ + fp::Fp, fp2::Fp2, multi_miller_loop, pairing, G1Affine, G1Projective, G2Affine, G2Prepared, + G2Projective, Scalar, +}; +use ff::Field; +use group::Group; +use rand::thread_rng; + +sp1_zkvm::entrypoint!(main); + +pub fn main() { + // Fp operations + { + let lhs = Fp::random(&mut rand::thread_rng()); + let rhs = Fp::random(&mut rand::thread_rng()); + let lhs = Fp::one(); + let rhs = Fp::one(); + + println!("cycle-tracker-start: bls12_381-add-fp"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bls12_381-add-fp"); + println!("cycle-tracker-start: bls12_381-sub-fp"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bls12_381-sub-fp"); + println!("cycle-tracker-start: bls12_381-mul-fp"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bls12_381-mul-fp"); + } + + // Scalar operations + { + let lhs = Scalar::random(&mut rand::thread_rng()); + let rhs = Scalar::random(&mut rand::thread_rng()); + println!("cycle-tracker-start: bls12_381-add-scalar"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bls12_381-add-scalar"); + println!("cycle-tracker-start: bls12_381-sub-scalar"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bls12_381-sub-scalar"); + println!("cycle-tracker-start: bls12_381-mul-scalar"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bls12_381-mul-scalar"); + } + + // Fp2 operations + { + let lhs = Fp2::random(&mut rand::thread_rng()); + let rhs = Fp2::random(&mut rand::thread_rng()); + println!("cycle-tracker-start: bls12_381-add-fp2"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bls12_381-add-fp2"); + println!("cycle-tracker-start: bls12_381-sub-fp2"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bls12_381-sub-fp2"); + println!("cycle-tracker-start: bls12_381-mul-fp2"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bls12_381-mul-fp2"); + } + + // G1 operations + { + let lhs = G1Projective::random(&mut rand::thread_rng()); + let rhs = G1Projective::random(&mut rand::thread_rng()); + println!("cycle-tracker-start: bls12_381-add-g1"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bls12_381-add-g1"); + println!("cycle-tracker-start: bls12_381-mul-g1"); + let _ = lhs * Scalar::random(&mut rand::thread_rng()); + println!("cycle-tracker-end: bls12_381-mul-g1"); + } + + // G2 operations + { + let lhs = G2Projective::random(&mut rand::thread_rng()); + let rhs = G2Projective::random(&mut rand::thread_rng()); + println!("cycle-tracker-start: bls12_381-add-g2"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bls12_381-add-g2"); + println!("cycle-tracker-start: bls12_381-mul-g2"); + let _ = lhs * Scalar::random(&mut rand::thread_rng()); + println!("cycle-tracker-end: bls12_381-mul-g2"); + } + + // Pairing + { + let p1 = G1Affine::from(G1Projective::random(&mut rand::thread_rng())); + let p2 = G2Affine::from(G2Projective::random(&mut rand::thread_rng())); + println!("cycle-tracker-start: bls12_381-pairing"); + let _ = pairing(&p1, &p2); + println!("cycle-tracker-end: bls12_381-pairing"); + } + + // Pairing Check + { + let p1 = G1Affine::from(G1Projective::random(&mut rand::thread_rng())); + let q1 = G2Affine::from(G2Projective::random(&mut rand::thread_rng())); + let p2 = G1Affine::from(G1Projective::random(&mut rand::thread_rng())); + let q2 = G2Affine::from(G2Projective::random(&mut rand::thread_rng())); + println!("cycle-tracker-start: bls12_381-pairing-check"); + multi_miller_loop(&[(&p1, &G2Prepared::from(q1)), (&p2, &G2Prepared::from(q2))]) + .final_exponentiation(); + println!("cycle-tracker-end: bls12_381-pairing-check"); + } +} diff --git a/examples/bls12381/script/Cargo.lock b/examples/bls12381/script/Cargo.lock new file mode 100644 index 0000000000..2482ece3d1 --- /dev/null +++ b/examples/bls12381/script/Cargo.lock @@ -0,0 +1,6338 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[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.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +dependencies = [ + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.75", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "syn 2.0.75", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayref" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "serde", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.75", + "which", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "rayon-core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "bls12381-script" +version = "0.1.0" +dependencies = [ + "sp1-helper", + "sp1-sdk", +] + +[[package]] +name = "bls12_381" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" +dependencies = [ + "ff 0.12.1", + "group 0.12.1", + "pairing", + "rand_core", + "subtle", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +dependencies = [ + "serde", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.23", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version 0.4.0", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.75", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "dashu" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b3e5ac1e23ff1995ef05b912e2b012a8784506987a2651552db2c73fb3d7e0" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-macros", + "dashu-ratio", + "rustversion", +] + +[[package]] +name = "dashu-base" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b80bf6b85aa68c58ffea2ddb040109943049ce3fbdf4385d0380aef08ef289" + +[[package]] +name = "dashu-float" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85078445a8dbd2e1bd21f04a816f352db8d333643f0c9b78ca7c3d1df71063e7" +dependencies = [ + "dashu-base", + "dashu-int", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-int" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee99d08031ca34a4d044efbbb21dff9b8c54bb9d8c82a189187c0651ffdb9fbf" +dependencies = [ + "cfg-if", + "dashu-base", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93381c3ef6366766f6e9ed9cf09e4ef9dec69499baf04f0c60e70d653cf0ab10" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-ratio", + "paste", + "proc-macro2", + "quote", + "rustversion", +] + +[[package]] +name = "dashu-ratio" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33b04dd7ce1ccf8a02a69d3419e354f2bbfdf4eb911a0b7465487248764c9" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "num-modular", + "num-order", + "rustversion", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.75", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "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 = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.75", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.75", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum 0.7.3", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.75", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.12", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core", + "subtle", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96512db27971c2c3eece70a1e106fbe6c87760234e31e8f7e5634912fe52794a" +dependencies = [ + "serde", + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "memuse", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halo2" +version = "0.1.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a23c779b38253fe1538102da44ad5bd5378495a61d2c4ee18d64eaa61ae5995" +dependencies = [ + "halo2_proofs", +] + +[[package]] +name = "halo2_proofs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "pasta_curves 0.4.1", + "rand_core", + "rayon", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "jubjub" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f" +dependencies = [ + "bitvec", + "bls12_381", + "ff 0.12.1", + "group 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "libz-sys" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memuse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint 0.4.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oneshot" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p3-air" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e909ef66fa5d77ff0fd3cb5af4b33b27fa6fb68d02b9b1e70edbc29383e565" +dependencies = [ + "p3-field", + "p3-matrix", +] + +[[package]] +name = "p3-baby-bear" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46965470aac1cddfe52f535424b59d52f2fffef0fdeb9dbed19da39b1d8f048a" +dependencies = [ + "num-bigint 0.4.6", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-blake3" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ef32d6ea21dd5cf9fec8a31bf0c64e6ceee8901dbf50966b83a443093c2aba" +dependencies = [ + "blake3", + "p3-symmetric", +] + +[[package]] +name = "p3-bn254-fr" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3edfca6be3b3109adf8e3330baec30c3fc5f9f4d63d27aaec1b471ca51ed67" +dependencies = [ + "ff 0.13.0", + "num-bigint 0.4.6", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-challenger" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6662ea899a5d848b60c699944491d72757873b5e1fd46798e4712f90a03a4e9" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-commit" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3563918b5cc44ef5280bf9b51753e70dc78802de25e3fb81ed6c94617ccb6e" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-field", + "p3-matrix", + "p3-util", + "serde", +] + +[[package]] +name = "p3-dft" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510095701819d83c9509fe825bbf1ebfe50426ae75149df5fe1dcfd18261323a" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1977a0a65789f719aa824119c332c4676b000bdbfe94d312fb6244a70d601" +dependencies = [ + "itertools 0.12.1", + "num-bigint 0.4.6", + "num-traits", + "p3-util", + "rand", + "serde", +] + +[[package]] +name = "p3-fri" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22ddb958f200d9289cc73ff68847b0167ca0c14557b791dd9e318f98c2d1b28" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-interpolation" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d032cda212f6b408d7d5b0b9a8270a9455acb93742fe55a0880d82be8e90e500" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-util", +] + +[[package]] +name = "p3-keccak" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c56abdd5a8a780049d2f8e92cea1df57b55a2ef50a40d1103f2732f7a00e4b1" +dependencies = [ + "p3-symmetric", + "tiny-keccak", +] + +[[package]] +name = "p3-keccak-air" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8398f1694ccc38513df0b8cab5f9ef7325423f27cd9e4fa20bdc77d5079cf1b" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", + "tracing-forest", + "tracing-subscriber", +] + +[[package]] +name = "p3-matrix" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d548ee0b834f8e2ebc5037073acd101a3b0ca41a2d1d28a15ba0ccd9059495b0" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f5575d3d61bedb3e05681abb0f36b8bb339d65aa395d50756bfa64e9cd3f46" +dependencies = [ + "rayon", +] + +[[package]] +name = "p3-mds" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6e57ed310d59245f93e24ee805ea7aa16fc9c505551b76a15f5e50f29d177e" +dependencies = [ + "itertools 0.12.1", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand", +] + +[[package]] +name = "p3-merkle-tree" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af46b41cba75d483ec8a553cbab1d2d794935ae3403d75394acfa4fb2c977cce" +dependencies = [ + "itertools 0.12.1", + "p3-commit", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-poseidon2" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adaba6f14c197203530e233badce0ca1126ba3bf3c9ff766505b497bdad0bee1" +dependencies = [ + "gcd", + "p3-field", + "p3-mds", + "p3-symmetric", + "rand", +] + +[[package]] +name = "p3-symmetric" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ecc4282566eb14f48be7707f6745c4dff6be664984d59ec0fb1849cd82b5c2" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "serde", +] + +[[package]] +name = "p3-uni-stark" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1af5c038b22b058bf1d49fb1ea3dd6c240a3e46c3278fde5c444e0034f7ffe37" +dependencies = [ + "itertools 0.12.1", + "p3-air", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "postcard", + "serde", + "tracing", + "tracing-forest", + "tracing-subscriber", +] + +[[package]] +name = "p3-util" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79f3fef0e00d9d7246385e758c4cd39b4efcbbcea31752471491ab502631385e" +dependencies = [ + "serde", +] + +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group 0.12.1", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pasta_curves" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.0", + "group 0.13.0", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.0", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "portable-atomic" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" + +[[package]] +name = "postcard" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.75", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.4", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.0.0", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash 2.0.0", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rayon-scan" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f87cc11a0140b4b0da0ffc889885760c61b13672d80a908920b2c0df078fa14" +dependencies = [ + "rayon", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.0", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "reqwest-middleware" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" +dependencies = [ + "anyhow", + "async-trait", + "http 1.1.0", + "reqwest 0.12.7", + "serde", + "thiserror", + "tower-service", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rrs-succinct" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3372685893a9f67d18e98e792d690017287fd17379a83d798d958e517d380fa9" +dependencies = [ + "downcast-rs", + "num_enum 0.5.11", + "paste", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint 0.4.6", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[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 = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scc" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb7ac86243095b70a7920639507b71d51a63390d1ba26c4f60a552fbb914a37" +dependencies = [ + "sdd", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sdd" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "serde_json" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.4.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "serial_test" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "size" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "sp1-build" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "cargo_metadata", + "chrono", + "clap", + "dirs", +] + +[[package]] +name = "sp1-core-executor" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "bytemuck", + "elf", + "eyre", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "nohash-hasher", + "num", + "p3-field", + "p3-keccak-air", + "p3-maybe-rayon", + "rand", + "rrs-succinct", + "serde", + "serde_with", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "strum", + "strum_macros", + "thiserror", + "tiny-keccak", + "tracing", + "typenum", +] + +[[package]] +name = "sp1-core-machine" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "arrayref", + "bincode", + "blake3", + "bytemuck", + "cfg-if", + "curve25519-dalek", + "elf", + "elliptic-curve", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "k256", + "log", + "nohash-hasher", + "num", + "num-bigint 0.4.6", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-blake3", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-keccak", + "p3-keccak-air", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rand", + "rayon-scan", + "rrs-succinct", + "serde", + "serde_with", + "size", + "snowbridge-amcl", + "sp1-core-executor", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "tracing", + "tracing-forest", + "tracing-subscriber", + "typenum", + "web-time", +] + +[[package]] +name = "sp1-cuda" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "ctrlc", + "prost", + "prost-types", + "serde", + "serde_json", + "sp1-core-machine", + "sp1-prover", + "sp1-stark", + "tokio", + "tracing", + "tracing-subscriber", + "twirp-rs", +] + +[[package]] +name = "sp1-curves" +version = "1.2.0-rc1" +dependencies = [ + "curve25519-dalek", + "dashu", + "elliptic-curve", + "generic-array 1.1.0", + "itertools 0.13.0", + "k256", + "num", + "p3-field", + "serde", + "snowbridge-amcl", + "sp1-primitives", + "sp1-stark", + "typenum", +] + +[[package]] +name = "sp1-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-helper" +version = "1.2.0-rc1" +dependencies = [ + "sp1-build", +] + +[[package]] +name = "sp1-primitives" +version = "1.2.0-rc1" +dependencies = [ + "itertools 0.13.0", + "lazy_static", + "p3-baby-bear", + "p3-field", + "p3-poseidon2", + "p3-symmetric", +] + +[[package]] +name = "sp1-prover" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "bincode", + "clap", + "dirs", + "hex", + "itertools 0.13.0", + "num-bigint 0.4.6", + "oneshot", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-field", + "p3-matrix", + "rayon", + "serde", + "serde_json", + "serial_test", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-circuit", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-gnark-ffi", + "sp1-recursion-program", + "sp1-stark", + "subtle-encoding", + "tempfile", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sp1-recursion-circuit" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-util", + "serde", + "sp1-core-machine", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-derive", + "sp1-recursion-program", + "sp1-stark", +] + +[[package]] +name = "sp1-recursion-compiler" +version = "1.2.0-rc1" +dependencies = [ + "backtrace", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rayon", + "serde", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-core", + "sp1-recursion-core-v2", + "sp1-recursion-derive", + "sp1-stark", + "tracing", + "vec_map", +] + +[[package]] +name = "sp1-recursion-core" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "tracing", + "zkhash", +] + +[[package]] +name = "sp1-recursion-core-v2" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-recursion-core", + "sp1-stark", + "static_assertions", + "thiserror", + "tracing", + "vec_map", + "zkhash", +] + +[[package]] +name = "sp1-recursion-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-recursion-gnark-ffi" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "bincode", + "bindgen", + "cc", + "cfg-if", + "hex", + "log", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-field", + "p3-symmetric", + "rand", + "serde", + "serde_json", + "sha2", + "sp1-core-machine", + "sp1-recursion-compiler", + "sp1-stark", + "tempfile", +] + +[[package]] +name = "sp1-recursion-program" +version = "1.2.0-rc1" +dependencies = [ + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rand", + "serde", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-stark", + "stacker", + "tracing", +] + +[[package]] +name = "sp1-sdk" +version = "1.2.0-rc1" +dependencies = [ + "alloy-sol-types", + "anyhow", + "async-trait", + "axum", + "bincode", + "cfg-if", + "dirs", + "ethers", + "futures", + "hashbrown 0.14.5", + "hex", + "indicatif", + "log", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "prost", + "reqwest 0.12.7", + "reqwest-middleware", + "serde", + "serde_json", + "sha2", + "sp1-core-executor", + "sp1-core-machine", + "sp1-cuda", + "sp1-prover", + "sp1-stark", + "strum", + "strum_macros", + "sysinfo", + "tempfile", + "thiserror", + "tokio", + "tracing", + "twirp-rs", + "vergen", +] + +[[package]] +name = "sp1-stark" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rayon-scan", + "serde", + "sp1-derive", + "sp1-primitives", + "tracing", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stacker" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a5daa25ea337c85ed954c0496e3bdd2c7308cc3b24cf7b50d04876654c579f" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.36.1", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.75", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "sysinfo" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[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 = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.20", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.4.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.4.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap 2.4.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.18", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "twirp-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa3161d8eee0abcad4e762f4215381a430cc1281870d575b0f1e4fbfc74b8ce" +dependencies = [ + "async-trait", + "axum", + "bytes", + "futures", + "http 1.1.0", + "http-body-util", + "hyper 1.4.1", + "prost", + "reqwest 0.12.7", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "url", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "vergen" +version = "8.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" +dependencies = [ + "anyhow", + "cfg-if", + "git2", + "rustversion", + "time", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.75", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[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.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "zkhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4352d1081da6922701401cdd4cbf29a2723feb4cfabb5771f6fee8e9276da1c7" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", + "bitvec", + "blake2", + "bls12_381", + "byteorder", + "cfg-if", + "group 0.12.1", + "group 0.13.0", + "halo2", + "hex", + "jubjub", + "lazy_static", + "pasta_curves 0.5.1", + "rand", + "serde", + "sha2", + "sha3", + "subtle", +] diff --git a/examples/bls12381/script/Cargo.toml b/examples/bls12381/script/Cargo.toml new file mode 100644 index 0000000000..fece9d6966 --- /dev/null +++ b/examples/bls12381/script/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +[package] +version = "0.1.0" +name = "bls12381-script" +edition = "2021" + +[dependencies] +sp1-sdk = { path = "../../../../sp1/crates/sdk" } + + +[build-dependencies] +sp1-helper = { path = "../../../../sp1/crates/helper" } diff --git a/examples/bls12381/script/build.rs b/examples/bls12381/script/build.rs new file mode 100644 index 0000000000..32b99273cd --- /dev/null +++ b/examples/bls12381/script/build.rs @@ -0,0 +1,5 @@ +use sp1_helper::build_program; + +fn main() { + build_program("../program") +} diff --git a/examples/bls12381/script/rust-toolchain b/examples/bls12381/script/rust-toolchain new file mode 100644 index 0000000000..3a306210c9 --- /dev/null +++ b/examples/bls12381/script/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2024-04-17" +components = ["llvm-tools", "rustc-dev"] \ No newline at end of file diff --git a/examples/bls12381/script/src/main.rs b/examples/bls12381/script/src/main.rs new file mode 100644 index 0000000000..cc5936e386 --- /dev/null +++ b/examples/bls12381/script/src/main.rs @@ -0,0 +1,11 @@ +use sp1_sdk::{utils, ProverClient, SP1Stdin}; +pub const ELF: &[u8] = include_bytes!("../../../program/elf/riscv32im-succinct-zkvm-elf"); + +fn main() { + utils::setup_logger(); + + let mut stdin = SP1Stdin::new(); + + let client = ProverClient::new(); + let (mut public_values, _) = client.execute(ELF, stdin).run().expect("failed to prove"); +} diff --git a/tests/ecrecover/Cargo.lock b/examples/bn254/program/Cargo.lock similarity index 66% rename from tests/ecrecover/Cargo.lock rename to examples/bn254/program/Cargo.lock index 6e1140252a..5452d27978 100644 --- a/tests/ecrecover/Cargo.lock +++ b/examples/bn254/program/Cargo.lock @@ -9,22 +9,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "base16ct" -version = "0.2.0" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "base64ct" -version = "1.6.0" +name = "autocfg" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "bincode" @@ -35,18 +29,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -57,16 +39,39 @@ dependencies = [ ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "bn254" +version = "1.1.0" +dependencies = [ + "num", + "rand", + "serde_yaml", + "sp1-zkvm", + "substrate-bn", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] -name = "const-oid" -version = "0.9.6" +name = "bytemuck" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cpufeatures" @@ -78,16 +83,10 @@ dependencies = [ ] [[package]] -name = "crypto-bigint" -version = "0.5.5" +name = "crunchy" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" @@ -100,13 +99,14 @@ dependencies = [ ] [[package]] -name = "der" -version = "0.7.8" +name = "derive_more" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ - "const-oid", - "zeroize", + "proc-macro2", + "quote", + "syn 2.0.55", ] [[package]] @@ -116,71 +116,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ecrecover-test" -version = "0.1.0" -dependencies = [ - "hex-literal", - "k256", - "num", - "sp1-zkvm", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "tap", - "zeroize", ] [[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "bitvec", - "rand_core", - "subtle", -] - -[[package]] -name = "funty" -version = "2.0.0" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "generic-array" @@ -190,7 +133,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -205,50 +147,52 @@ dependencies = [ ] [[package]] -name = "group" -version = "0.13.0" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "hex-literal" -version = "0.4.1" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hmac" -version = "0.12.1" +name = "impl-trait-for-tuples" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "digest", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "k256" -version = "0.13.3" +name = "indexmap" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", - "signature", + "equivalent", + "hashbrown", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -262,6 +206,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "num" version = "0.4.3" @@ -330,13 +280,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "pkcs8" -version = "0.10.2" +name = "parity-scale-codec" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ - "der", - "spki", + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -345,6 +309,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.79" @@ -363,12 +336,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.8.5" @@ -400,47 +367,72 @@ dependencies = [ ] [[package]] -name = "rfc6979" -version = "0.4.0" +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "ryu" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ - "hmac", - "subtle", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", ] [[package]] -name = "sec1" -version = "0.7.3" +name = "scale-info-derive" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "serde" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.55", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] @@ -455,29 +447,43 @@ dependencies = [ ] [[package]] -name = "signature" -version = "2.2.0" +name = "snowbridge-amcl" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" dependencies = [ - "digest", - "rand_core", + "parity-scale-codec", + "scale-info", ] [[package]] name = "sp1-lib" -version = "0.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", - "k256", + "hex", "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +source = "git+https://github.com/succinctlabs/sp1?branch=dev#d3a73a9fc33351df68cf1f12625cd48b7415c77f" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "hex", + "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "0.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -488,24 +494,40 @@ dependencies = [ "rand", "serde", "sha2", - "sp1-lib", + "sp1-lib 1.1.1", ] [[package]] -name = "spki" -version = "0.7.3" +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "git+https://github.com/sp1-patches/bn?branch=bhargav/bn-optimizations#43d854d45b5727b1ff2b9f346d728e785bb8395c" dependencies = [ - "base64ct", - "der", + "bytemuck", + "byteorder", + "cfg-if", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", + "sp1-lib 1.1.1 (git+https://github.com/succinctlabs/sp1?branch=dev)", ] [[package]] -name = "subtle" -version = "2.5.0" +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" @@ -519,10 +541,21 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "toml_datetime" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] [[package]] name = "typenum" @@ -536,6 +569,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "version_check" version = "0.9.4" @@ -549,16 +588,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wyz" -version = "0.5.1" +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ - "tap", + "memchr", ] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/examples/bn254/program/Cargo.toml b/examples/bn254/program/Cargo.toml new file mode 100644 index 0000000000..8331b3e9d7 --- /dev/null +++ b/examples/bn254/program/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +[package] +name = "bn254" +version = "1.1.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } +num = { version = "0.4.1", default-features = false } +serde_yaml = "0.9.34" +bn = { git = "https://github.com/sp1-patches/bn", package = "substrate-bn", branch = "bhargav/bn-optimizations"} +# bn = { git = "https://github.com/sp1-patches/bn", package = "substrate-bn", branch = "patch-v0.6.0"} +rand = "0.8.5" diff --git a/examples/bn254/program/elf/riscv32im-succinct-zkvm-elf b/examples/bn254/program/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..4a25479725 Binary files /dev/null and b/examples/bn254/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/bn254/program/src/main.rs b/examples/bn254/program/src/main.rs new file mode 100644 index 0000000000..ecc385c4d7 --- /dev/null +++ b/examples/bn254/program/src/main.rs @@ -0,0 +1,108 @@ +#![no_main] + +use bn::{pairing, pairing_batch, Fq, Fq2, Fr, Group, G1, G2}; + +sp1_zkvm::entrypoint!(main); + +pub fn main() { + { + let lhs = Fq::random(&mut rand::thread_rng()); + let rhs = Fq::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-add-fp"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bn254-add-fp"); + + println!("cycle-tracker-start: bn254-sub-fp"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bn254-sub-fp"); + + println!("cycle-tracker-start: bn254-mul-fp"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bn254-mul-fp"); + } + + { + let lhs = Fr::random(&mut rand::thread_rng()); + let rhs = Fr::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-add-fr"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bn254-add-fr"); + + println!("cycle-tracker-start: bn254-sub-fr"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bn254-sub-fr"); + + println!("cycle-tracker-start: bn254-mul-fr"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bn254-mul-fr"); + } + + { + let lhs = + Fq2::new(Fq::random(&mut rand::thread_rng()), Fq::random(&mut rand::thread_rng())); + let rhs = + Fq2::new(Fq::random(&mut rand::thread_rng()), Fq::random(&mut rand::thread_rng())); + + println!("cycle-tracker-start: bn254-add-fq2"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bn254-add-fq2"); + + println!("cycle-tracker-start: bn254-sub-fq2"); + let _ = lhs - rhs; + println!("cycle-tracker-end: bn254-sub-fq2"); + + println!("cycle-tracker-start: bn254-mul-fq2"); + let _ = lhs * rhs; + println!("cycle-tracker-end: bn254-mul-fq2"); + } + + { + let lhs = G1::random(&mut rand::thread_rng()); + let rhs = G1::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-add-g1"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bn254-add-g1"); + + println!("cycle-tracker-start: bn254-mul-g1"); + let _ = lhs * Fr::random(&mut rand::thread_rng()); + println!("cycle-tracker-end: bn254-mul-g1"); + } + + { + { + let lhs = G2::random(&mut rand::thread_rng()); + let rhs = G2::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-add-g2"); + let _ = lhs + rhs; + println!("cycle-tracker-end: bn254-add-g2"); + + println!("cycle-tracker-start: bn254-mul-g2"); + let _ = lhs * Fr::random(&mut rand::thread_rng()); + println!("cycle-tracker-end: bn254-mul-g2"); + } + } + + { + let p1 = G1::random(&mut rand::thread_rng()); + let p2 = G2::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-pairing"); + let _ = pairing(p1, p2); + println!("cycle-tracker-end: bn254-pairing"); + } + + { + let p1 = G1::random(&mut rand::thread_rng()); + let q1 = G2::random(&mut rand::thread_rng()); + let p2 = G1::random(&mut rand::thread_rng()); + let q2 = G2::random(&mut rand::thread_rng()); + + println!("cycle-tracker-start: bn254-pairing-check"); + pairing_batch(&[(p1, q1), (p2, q2)]).final_exponentiation(); + println!("cycle-tracker-end: bn254-pairing-check"); + } +} diff --git a/examples/bn254/script/Cargo.lock b/examples/bn254/script/Cargo.lock new file mode 100644 index 0000000000..954b0d09fb --- /dev/null +++ b/examples/bn254/script/Cargo.lock @@ -0,0 +1,6294 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[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.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +dependencies = [ + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.68", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "syn 2.0.68", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayref" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "serde", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.68", + "which", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "rayon-core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "bls12_381" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" +dependencies = [ + "ff 0.12.1", + "group 0.12.1", + "pairing", + "rand_core", + "subtle", +] + +[[package]] +name = "bn254-script" +version = "0.1.0" +dependencies = [ + "sp1-helper", + "sp1-sdk", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +dependencies = [ + "serde", +] + +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.23", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version 0.4.0", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.68", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "dashu" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b3e5ac1e23ff1995ef05b912e2b012a8784506987a2651552db2c73fb3d7e0" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-macros", + "dashu-ratio", + "rustversion", +] + +[[package]] +name = "dashu-base" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b80bf6b85aa68c58ffea2ddb040109943049ce3fbdf4385d0380aef08ef289" + +[[package]] +name = "dashu-float" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85078445a8dbd2e1bd21f04a816f352db8d333643f0c9b78ca7c3d1df71063e7" +dependencies = [ + "dashu-base", + "dashu-int", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-int" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee99d08031ca34a4d044efbbb21dff9b8c54bb9d8c82a189187c0651ffdb9fbf" +dependencies = [ + "cfg-if", + "dashu-base", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93381c3ef6366766f6e9ed9cf09e4ef9dec69499baf04f0c60e70d653cf0ab10" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-ratio", + "paste", + "proc-macro2", + "quote", + "rustversion", +] + +[[package]] +name = "dashu-ratio" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33b04dd7ce1ccf8a02a69d3419e354f2bbfdf4eb911a0b7465487248764c9" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "num-modular", + "num-order", + "rustversion", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.68", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "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 = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.68", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.68", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum 0.7.3", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.68", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.12", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core", + "subtle", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96512db27971c2c3eece70a1e106fbe6c87760234e31e8f7e5634912fe52794a" +dependencies = [ + "serde", + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.5.0", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "memuse", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.4.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halo2" +version = "0.1.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a23c779b38253fe1538102da44ad5bd5378495a61d2c4ee18d64eaa61ae5995" +dependencies = [ + "halo2_proofs", +] + +[[package]] +name = "halo2_proofs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "pasta_curves 0.4.1", + "rand_core", + "rayon", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "jubjub" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f" +dependencies = [ + "bitvec", + "bls12_381", + "ff 0.12.1", + "group 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.48.5", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "libz-sys" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memuse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint 0.4.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oneshot" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p3-air" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e909ef66fa5d77ff0fd3cb5af4b33b27fa6fb68d02b9b1e70edbc29383e565" +dependencies = [ + "p3-field", + "p3-matrix", +] + +[[package]] +name = "p3-baby-bear" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46965470aac1cddfe52f535424b59d52f2fffef0fdeb9dbed19da39b1d8f048a" +dependencies = [ + "num-bigint 0.4.6", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-blake3" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ef32d6ea21dd5cf9fec8a31bf0c64e6ceee8901dbf50966b83a443093c2aba" +dependencies = [ + "blake3", + "p3-symmetric", +] + +[[package]] +name = "p3-bn254-fr" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3edfca6be3b3109adf8e3330baec30c3fc5f9f4d63d27aaec1b471ca51ed67" +dependencies = [ + "ff 0.13.0", + "num-bigint 0.4.6", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + +[[package]] +name = "p3-challenger" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6662ea899a5d848b60c699944491d72757873b5e1fd46798e4712f90a03a4e9" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-commit" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3563918b5cc44ef5280bf9b51753e70dc78802de25e3fb81ed6c94617ccb6e" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-field", + "p3-matrix", + "p3-util", + "serde", +] + +[[package]] +name = "p3-dft" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510095701819d83c9509fe825bbf1ebfe50426ae75149df5fe1dcfd18261323a" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1977a0a65789f719aa824119c332c4676b000bdbfe94d312fb6244a70d601" +dependencies = [ + "itertools 0.12.1", + "num-bigint 0.4.6", + "num-traits", + "p3-util", + "rand", + "serde", +] + +[[package]] +name = "p3-fri" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22ddb958f200d9289cc73ff68847b0167ca0c14557b791dd9e318f98c2d1b28" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-interpolation" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d032cda212f6b408d7d5b0b9a8270a9455acb93742fe55a0880d82be8e90e500" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-util", +] + +[[package]] +name = "p3-keccak" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c56abdd5a8a780049d2f8e92cea1df57b55a2ef50a40d1103f2732f7a00e4b1" +dependencies = [ + "p3-symmetric", + "tiny-keccak", +] + +[[package]] +name = "p3-keccak-air" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8398f1694ccc38513df0b8cab5f9ef7325423f27cd9e4fa20bdc77d5079cf1b" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", + "tracing-forest", + "tracing-subscriber", +] + +[[package]] +name = "p3-matrix" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d548ee0b834f8e2ebc5037073acd101a3b0ca41a2d1d28a15ba0ccd9059495b0" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f5575d3d61bedb3e05681abb0f36b8bb339d65aa395d50756bfa64e9cd3f46" +dependencies = [ + "rayon", +] + +[[package]] +name = "p3-mds" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6e57ed310d59245f93e24ee805ea7aa16fc9c505551b76a15f5e50f29d177e" +dependencies = [ + "itertools 0.12.1", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand", +] + +[[package]] +name = "p3-merkle-tree" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af46b41cba75d483ec8a553cbab1d2d794935ae3403d75394acfa4fb2c977cce" +dependencies = [ + "itertools 0.12.1", + "p3-commit", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-poseidon2" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adaba6f14c197203530e233badce0ca1126ba3bf3c9ff766505b497bdad0bee1" +dependencies = [ + "gcd", + "p3-field", + "p3-mds", + "p3-symmetric", + "rand", +] + +[[package]] +name = "p3-symmetric" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ecc4282566eb14f48be7707f6745c4dff6be664984d59ec0fb1849cd82b5c2" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "serde", +] + +[[package]] +name = "p3-uni-stark" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1af5c038b22b058bf1d49fb1ea3dd6c240a3e46c3278fde5c444e0034f7ffe37" +dependencies = [ + "itertools 0.12.1", + "p3-air", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "postcard", + "serde", + "tracing", + "tracing-forest", + "tracing-subscriber", +] + +[[package]] +name = "p3-util" +version = "0.1.3-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79f3fef0e00d9d7246385e758c4cd39b4efcbbcea31752471491ab502631385e" +dependencies = [ + "serde", +] + +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group 0.12.1", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pasta_curves" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.0", + "group 0.13.0", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.0", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "portable-atomic" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" + +[[package]] +name = "postcard" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.68", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.5.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.4", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.0.0", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash 2.0.0", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rayon-scan" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f87cc11a0140b4b0da0ffc889885760c61b13672d80a908920b2c0df078fa14" +dependencies = [ + "rayon", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.0", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "reqwest-middleware" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" +dependencies = [ + "anyhow", + "async-trait", + "http 1.1.0", + "reqwest 0.12.7", + "serde", + "thiserror", + "tower-service", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rrs-succinct" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3372685893a9f67d18e98e792d690017287fd17379a83d798d958e517d380fa9" +dependencies = [ + "downcast-rs", + "num_enum 0.5.11", + "paste", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint 0.4.6", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[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 = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scc" +version = "2.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb7ac86243095b70a7920639507b71d51a63390d1ba26c4f60a552fbb914a37" +dependencies = [ + "sdd", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sdd" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serde_json" +version = "1.0.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.4.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serial_test" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "size" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "sp1-build" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "cargo_metadata", + "chrono", + "clap", + "dirs", +] + +[[package]] +name = "sp1-core-executor" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "bytemuck", + "elf", + "eyre", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "nohash-hasher", + "num", + "p3-field", + "p3-keccak-air", + "p3-maybe-rayon", + "rand", + "rrs-succinct", + "serde", + "serde_with", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "strum", + "strum_macros", + "thiserror", + "tiny-keccak", + "tracing", + "typenum", +] + +[[package]] +name = "sp1-core-machine" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "arrayref", + "bincode", + "blake3", + "bytemuck", + "cfg-if", + "curve25519-dalek", + "elf", + "elliptic-curve", + "generic-array 1.1.0", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "k256", + "log", + "nohash-hasher", + "num", + "num-bigint 0.4.6", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-blake3", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-keccak", + "p3-keccak-air", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rand", + "rayon-scan", + "rrs-succinct", + "serde", + "serde_with", + "size", + "snowbridge-amcl", + "sp1-core-executor", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "tracing", + "tracing-forest", + "tracing-subscriber", + "typenum", + "web-time", +] + +[[package]] +name = "sp1-cuda" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "ctrlc", + "prost", + "prost-types", + "serde", + "serde_json", + "sp1-core-machine", + "sp1-prover", + "sp1-stark", + "tokio", + "tracing", + "tracing-subscriber", + "twirp-rs", +] + +[[package]] +name = "sp1-curves" +version = "1.2.0-rc1" +dependencies = [ + "curve25519-dalek", + "dashu", + "elliptic-curve", + "generic-array 1.1.0", + "itertools 0.13.0", + "k256", + "num", + "p3-field", + "serde", + "snowbridge-amcl", + "sp1-primitives", + "sp1-stark", + "typenum", +] + +[[package]] +name = "sp1-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-helper" +version = "1.2.0-rc1" +dependencies = [ + "sp1-build", +] + +[[package]] +name = "sp1-primitives" +version = "1.2.0-rc1" +dependencies = [ + "itertools 0.13.0", + "lazy_static", + "p3-baby-bear", + "p3-field", + "p3-poseidon2", + "p3-symmetric", +] + +[[package]] +name = "sp1-prover" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "bincode", + "clap", + "dirs", + "hex", + "itertools 0.13.0", + "num-bigint 0.4.6", + "oneshot", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-field", + "p3-matrix", + "rayon", + "serde", + "serde_json", + "serial_test", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-circuit", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-gnark-ffi", + "sp1-recursion-program", + "sp1-stark", + "subtle-encoding", + "tempfile", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sp1-recursion-circuit" +version = "1.2.0-rc1" +dependencies = [ + "bincode", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-util", + "serde", + "sp1-core-machine", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-derive", + "sp1-recursion-program", + "sp1-stark", +] + +[[package]] +name = "sp1-recursion-compiler" +version = "1.2.0-rc1" +dependencies = [ + "backtrace", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rayon", + "serde", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-core", + "sp1-recursion-core-v2", + "sp1-recursion-derive", + "sp1-stark", + "tracing", + "vec_map", +] + +[[package]] +name = "sp1-recursion-core" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "tracing", + "zkhash", +] + +[[package]] +name = "sp1-recursion-core-v2" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "serde_with", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-recursion-core", + "sp1-stark", + "static_assertions", + "thiserror", + "tracing", + "vec_map", + "zkhash", +] + +[[package]] +name = "sp1-recursion-derive" +version = "1.2.0-rc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-recursion-gnark-ffi" +version = "1.2.0-rc1" +dependencies = [ + "anyhow", + "bincode", + "bindgen", + "cc", + "cfg-if", + "hex", + "log", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-field", + "p3-symmetric", + "rand", + "serde", + "serde_json", + "sha2", + "sp1-core-machine", + "sp1-recursion-compiler", + "sp1-stark", + "tempfile", +] + +[[package]] +name = "sp1-recursion-program" +version = "1.2.0-rc1" +dependencies = [ + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "rand", + "serde", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-stark", + "stacker", + "tracing", +] + +[[package]] +name = "sp1-sdk" +version = "1.2.0-rc1" +dependencies = [ + "alloy-sol-types", + "anyhow", + "async-trait", + "axum", + "bincode", + "cfg-if", + "dirs", + "ethers", + "futures", + "hashbrown 0.14.5", + "hex", + "indicatif", + "log", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-commit", + "p3-field", + "p3-fri", + "p3-matrix", + "prost", + "reqwest 0.12.7", + "reqwest-middleware", + "serde", + "serde_json", + "sha2", + "sp1-core-executor", + "sp1-core-machine", + "sp1-cuda", + "sp1-prover", + "sp1-stark", + "strum", + "strum_macros", + "sysinfo", + "tempfile", + "thiserror", + "tokio", + "tracing", + "twirp-rs", + "vergen", +] + +[[package]] +name = "sp1-stark" +version = "1.2.0-rc1" +dependencies = [ + "arrayref", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rayon-scan", + "serde", + "sp1-derive", + "sp1-primitives", + "tracing", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.68", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "sysinfo" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[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 = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.20", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.4.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.4.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap 2.4.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.18", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "twirp-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa3161d8eee0abcad4e762f4215381a430cc1281870d575b0f1e4fbfc74b8ce" +dependencies = [ + "async-trait", + "axum", + "bytes", + "futures", + "http 1.1.0", + "http-body-util", + "hyper 1.4.1", + "prost", + "reqwest 0.12.7", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "url", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "vergen" +version = "8.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" +dependencies = [ + "anyhow", + "cfg-if", + "git2", + "rustversion", + "time", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.68", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[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.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "zkhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4352d1081da6922701401cdd4cbf29a2723feb4cfabb5771f6fee8e9276da1c7" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", + "bitvec", + "blake2", + "bls12_381", + "byteorder", + "cfg-if", + "group 0.12.1", + "group 0.13.0", + "halo2", + "hex", + "jubjub", + "lazy_static", + "pasta_curves 0.5.1", + "rand", + "serde", + "sha2", + "sha3", + "subtle", +] diff --git a/examples/bn254/script/Cargo.toml b/examples/bn254/script/Cargo.toml new file mode 100644 index 0000000000..bf75e2f870 --- /dev/null +++ b/examples/bn254/script/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +[package] +version = "0.1.0" +name = "bn254-script" +edition = "2021" + +[dependencies] +sp1-sdk = { path = "../../../../sp1/crates/sdk" } + + +[build-dependencies] +sp1-helper = { path = "../../../../sp1/crates/helper" } diff --git a/examples/bn254/script/build.rs b/examples/bn254/script/build.rs new file mode 100644 index 0000000000..32b99273cd --- /dev/null +++ b/examples/bn254/script/build.rs @@ -0,0 +1,5 @@ +use sp1_helper::build_program; + +fn main() { + build_program("../program") +} diff --git a/examples/bn254/script/rust-toolchain b/examples/bn254/script/rust-toolchain new file mode 100644 index 0000000000..3a306210c9 --- /dev/null +++ b/examples/bn254/script/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2024-04-17" +components = ["llvm-tools", "rustc-dev"] \ No newline at end of file diff --git a/examples/bn254/script/src/main.rs b/examples/bn254/script/src/main.rs new file mode 100644 index 0000000000..cc5936e386 --- /dev/null +++ b/examples/bn254/script/src/main.rs @@ -0,0 +1,11 @@ +use sp1_sdk::{utils, ProverClient, SP1Stdin}; +pub const ELF: &[u8] = include_bytes!("../../../program/elf/riscv32im-succinct-zkvm-elf"); + +fn main() { + utils::setup_logger(); + + let mut stdin = SP1Stdin::new(); + + let client = ProverClient::new(); + let (mut public_values, _) = client.execute(ELF, stdin).run().expect("failed to prove"); +} diff --git a/examples/chess/program/Cargo.lock b/examples/chess/program/Cargo.lock index af91bdda0b..43da74aea7 100644 --- a/examples/chess/program/Cargo.lock +++ b/examples/chess/program/Cargo.lock @@ -29,6 +29,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "backtrace" version = "0.3.71" @@ -62,6 +68,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cc" version = "1.0.95" @@ -80,7 +92,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ed299b171ec34f372945ad6726f7bc1d2afd5f59fb8380f64f48e2bab2f0ec8" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "failure", "nodrop", "rand 0.7.3", @@ -113,6 +125,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -123,6 +146,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "failure" version = "0.1.8" @@ -172,6 +201,39 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -226,12 +288,45 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec 0.7.6", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -332,6 +427,30 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -363,19 +482,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -423,6 +554,23 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -452,3 +600,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/chess/program/Cargo.toml b/examples/chess/program/Cargo.toml index 0f706c254f..70dd44f3c6 100644 --- a/examples/chess/program/Cargo.toml +++ b/examples/chess/program/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } chess = "3.2.0" diff --git a/examples/chess/program/elf/riscv32im-succinct-zkvm-elf b/examples/chess/program/elf/riscv32im-succinct-zkvm-elf index a0b1a26d00..01a06d479f 100755 Binary files a/examples/chess/program/elf/riscv32im-succinct-zkvm-elf and b/examples/chess/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/chess/script/Cargo.toml b/examples/chess/script/Cargo.toml index cfa637b66f..0d1194077a 100644 --- a/examples/chess/script/Cargo.toml +++ b/examples/chess/script/Cargo.toml @@ -8,4 +8,4 @@ publish = false sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/chess/script/build.rs b/examples/chess/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/chess/script/build.rs +++ b/examples/chess/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/cycle-tracking/program/Cargo.lock b/examples/cycle-tracking/program/Cargo.lock index 09f5e2bf85..8438fe5e7f 100644 --- a/examples/cycle-tracking/program/Cargo.lock +++ b/examples/cycle-tracking/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "bincode" version = "1.3.3" @@ -26,6 +32,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -59,6 +71,17 @@ dependencies = [ "sp1-zkvm", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -69,6 +92,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "generic-array" version = "0.14.7" @@ -90,6 +119,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -108,18 +170,57 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -168,6 +269,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -199,9 +324,19 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-derive" -version = "1.1.0" +version = "1.1.1" dependencies = [ "proc-macro2", "quote", @@ -210,17 +345,19 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -256,6 +393,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -279,3 +433,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/cycle-tracking/program/Cargo.toml b/examples/cycle-tracking/program/Cargo.toml index fbe98f6940..4783257916 100644 --- a/examples/cycle-tracking/program/Cargo.toml +++ b/examples/cycle-tracking/program/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } -sp1-derive = { path = "../../../derive" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } +sp1-derive = { path = "../../../crates/derive" } diff --git a/examples/cycle-tracking/program/bin/normal.rs b/examples/cycle-tracking/program/bin/normal.rs new file mode 100644 index 0000000000..cfffe0efe7 --- /dev/null +++ b/examples/cycle-tracking/program/bin/normal.rs @@ -0,0 +1,32 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +#[sp1_derive::cycle_tracker] +pub fn expensive_function(x: usize) -> usize { + let mut y = 1; + for _ in 0..100 { + y *= x; + y %= 7919; + } + y +} + +pub fn main() { + let mut nums = vec![1, 1]; + + // Setup a large vector with Fibonacci-esque numbers. + println!("cycle-tracker-start: setup"); + for _ in 0..100 { + let mut c = nums[nums.len() - 1] + nums[nums.len() - 2]; + c %= 7919; + nums.push(c); + } + println!("cycle-tracker-end: setup"); + + println!("cycle-tracker-start: main-body"); + for i in 0..2 { + let result = expensive_function(nums[nums.len() - i - 1]); + println!("result: {}", result); + } + println!("cycle-tracker-end: main-body"); +} diff --git a/examples/cycle-tracking/program/bin/report.rs b/examples/cycle-tracking/program/bin/report.rs new file mode 100644 index 0000000000..e60ce2e2af --- /dev/null +++ b/examples/cycle-tracking/program/bin/report.rs @@ -0,0 +1,25 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +#[sp1_derive::cycle_tracker] +pub fn expensive_function(x: usize) -> usize { + let mut y = 1; + for _ in 0..100 { + y *= x; + y %= 7919; + } + y +} + +pub fn main() { + let mut nums = vec![1, 1]; + + // Setup a large vector with Fibonacci-esque numbers. + println!("cycle-tracker-report-start: setup"); + for _ in 0..100 { + let mut c = nums[nums.len() - 1] + nums[nums.len() - 2]; + c %= 7919; + nums.push(c); + } + println!("cycle-tracker-report-end: setup"); +} diff --git a/examples/cycle-tracking/program/elf/normal b/examples/cycle-tracking/program/elf/normal new file mode 100755 index 0000000000..812a0f97a3 Binary files /dev/null and b/examples/cycle-tracking/program/elf/normal differ diff --git a/examples/cycle-tracking/program/elf/report b/examples/cycle-tracking/program/elf/report new file mode 100755 index 0000000000..afcc118fd0 Binary files /dev/null and b/examples/cycle-tracking/program/elf/report differ diff --git a/examples/cycle-tracking/program/elf/riscv32im-succinct-zkvm-elf b/examples/cycle-tracking/program/elf/riscv32im-succinct-zkvm-elf index 593ceec7b0..e752640133 100755 Binary files a/examples/cycle-tracking/program/elf/riscv32im-succinct-zkvm-elf and b/examples/cycle-tracking/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/cycle-tracking/script/Cargo.toml b/examples/cycle-tracking/script/Cargo.toml index fb8ef7774b..1b6dbc3cfd 100644 --- a/examples/cycle-tracking/script/Cargo.toml +++ b/examples/cycle-tracking/script/Cargo.toml @@ -8,4 +8,4 @@ publish = false sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/cycle-tracking/script/build.rs b/examples/cycle-tracking/script/build.rs index 32b99273cd..2e503ae98c 100644 --- a/examples/cycle-tracking/script/build.rs +++ b/examples/cycle-tracking/script/build.rs @@ -1,4 +1,4 @@ -use sp1_helper::build_program; +use sp1_build::build_program; fn main() { build_program("../program") diff --git a/examples/fibonacci/program/Cargo.lock b/examples/fibonacci/program/Cargo.lock index af71fc09ec..c3079154b8 100644 --- a/examples/fibonacci/program/Cargo.lock +++ b/examples/fibonacci/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "bincode" version = "1.3.3" @@ -26,6 +32,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -51,6 +63,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -61,6 +84,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fibonacci-program" version = "1.1.0" @@ -89,6 +118,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -107,18 +169,57 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -167,6 +268,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -184,7 +309,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -198,19 +323,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.2.0-rc1" dependencies = [ "bincode", "cfg-if", @@ -224,6 +361,17 @@ dependencies = [ "sp1-lib", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.60" @@ -235,6 +383,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -258,3 +423,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/fibonacci/program/Cargo.toml b/examples/fibonacci/program/Cargo.toml index ade806cdcc..99864b4b39 100644 --- a/examples/fibonacci/program/Cargo.toml +++ b/examples/fibonacci/program/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 14f3c9f5f0..41b281e4ae 100755 Binary files a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf and b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/fibonacci/script/Cargo.toml b/examples/fibonacci/script/Cargo.toml index 6054ede538..e8b0ebeeba 100644 --- a/examples/fibonacci/script/Cargo.toml +++ b/examples/fibonacci/script/Cargo.toml @@ -11,7 +11,7 @@ sp1-sdk = { workspace = true } sha2 = "0.10.8" [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } [[bin]] name = "plonk_bn254" @@ -28,3 +28,6 @@ path = "bin/execute.rs" [[bin]] name = "fibonacci-script" path = "src/main.rs" + +[features] +cuda = ["sp1-sdk/cuda"] diff --git a/examples/fibonacci/script/build.rs b/examples/fibonacci/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/fibonacci/script/build.rs +++ b/examples/fibonacci/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/fibonacci/script/src/main.rs b/examples/fibonacci/script/src/main.rs index 9f5a81f256..c61f93e366 100644 --- a/examples/fibonacci/script/src/main.rs +++ b/examples/fibonacci/script/src/main.rs @@ -19,22 +19,22 @@ fn main() { let client = ProverClient::new(); // Execute the program using the `ProverClient.execute` method, without generating a proof. - let (_public_values, report) = client.execute(ELF, stdin.clone()).run().unwrap(); + let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap(); println!( - "Executed program with {} cycles", + "executed program with {} cycles", report.total_instruction_count() ); // Generate the proof for the given program and input. - let client = ProverClient::new(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); println!("generated proof"); // Read and verify the output. - // Note that this output is read from values commited to in the program - // using `sp1_zkvm::io::commit`. + // + // Note that this output is read from values commited to in the program using + // `sp1_zkvm::io::commit`. let _ = proof.public_values.read::(); let a = proof.public_values.read::(); let b = proof.public_values.read::(); diff --git a/examples/io/program/Cargo.lock b/examples/io/program/Cargo.lock index 07344ff87e..99d7258ba2 100644 --- a/examples/io/program/Cargo.lock +++ b/examples/io/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "bincode" version = "1.3.3" @@ -26,6 +32,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -51,6 +63,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -61,6 +84,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "generic-array" version = "0.14.7" @@ -82,6 +111,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "io-program" version = "1.1.0" @@ -108,18 +170,57 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -168,6 +269,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -185,7 +310,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -199,19 +324,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -225,6 +362,17 @@ dependencies = [ "sp1-lib", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.60" @@ -236,6 +384,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -259,3 +424,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/io/program/Cargo.toml b/examples/io/program/Cargo.toml index 67bcbb2bce..3dfe8c5ce1 100644 --- a/examples/io/program/Cargo.toml +++ b/examples/io/program/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } serde = { version = "1.0.195", features = ["derive"] } diff --git a/examples/io/program/elf/riscv32im-succinct-zkvm-elf b/examples/io/program/elf/riscv32im-succinct-zkvm-elf index a9b731a22f..3429f4bee4 100755 Binary files a/examples/io/program/elf/riscv32im-succinct-zkvm-elf and b/examples/io/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/io/script/Cargo.toml b/examples/io/script/Cargo.toml index fbda365c6c..6297b360fe 100644 --- a/examples/io/script/Cargo.toml +++ b/examples/io/script/Cargo.toml @@ -9,4 +9,4 @@ serde = { version = "1.0.196", features = ["derive"] } sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/io/script/build.rs b/examples/io/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/io/script/build.rs +++ b/examples/io/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/is-prime/program/Cargo.toml b/examples/is-prime/program/Cargo.toml index 9852131132..2f85c02f3c 100644 --- a/examples/is-prime/program/Cargo.toml +++ b/examples/is-prime/program/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } diff --git a/examples/json/program/Cargo.lock b/examples/json/program/Cargo.lock index cfb659286e..b57093df70 100644 --- a/examples/json/program/Cargo.lock +++ b/examples/json/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "bincode" version = "1.3.3" @@ -26,6 +32,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -51,6 +63,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -61,6 +84,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "generic-array" version = "0.14.7" @@ -82,6 +111,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.11" @@ -123,18 +185,57 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -189,6 +290,30 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -206,7 +331,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -231,19 +356,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -257,6 +394,17 @@ dependencies = [ "sp1-lib", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.60" @@ -268,6 +416,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -291,3 +456,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/json/program/Cargo.toml b/examples/json/program/Cargo.toml index 9e1ffe6aca..5d283c9fd6 100644 --- a/examples/json/program/Cargo.toml +++ b/examples/json/program/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } serde_json = "1.0.113" serde = "1.0.197" lib = { path = "../lib" } diff --git a/examples/json/program/elf/riscv32im-succinct-zkvm-elf b/examples/json/program/elf/riscv32im-succinct-zkvm-elf index 428eabcdf7..1a74fe1a1c 100755 Binary files a/examples/json/program/elf/riscv32im-succinct-zkvm-elf and b/examples/json/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/json/script/Cargo.toml b/examples/json/script/Cargo.toml index 796c53eff6..860202fbfb 100644 --- a/examples/json/script/Cargo.toml +++ b/examples/json/script/Cargo.toml @@ -11,4 +11,4 @@ sp1-sdk = { workspace = true } lib = { path = "../lib" } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/json/script/build.rs b/examples/json/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/json/script/build.rs +++ b/examples/json/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/patch-testing/program/Cargo.lock b/examples/patch-testing/program/Cargo.lock index d6c90985d8..306b5ac40a 100644 --- a/examples/patch-testing/program/Cargo.lock +++ b/examples/patch-testing/program/Cargo.lock @@ -363,7 +363,7 @@ dependencies = [ "digest 0.10.7", "fiat-crypto", "rustc_version 0.4.0", - "sp1-lib 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp1-lib 1.1.0", "subtle", "zeroize", ] @@ -388,7 +388,7 @@ dependencies = [ "cfg-if", "digest 0.9.0", "rand_core", - "sp1-lib 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp1-lib 1.1.0", "subtle-ng", "zeroize", ] @@ -461,7 +461,7 @@ dependencies = [ "hex-literal", "rfc6979", "signature", - "sp1-lib 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp1-lib 1.1.0", "spki", ] @@ -1093,6 +1093,30 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sec1" version = "0.7.3" @@ -1214,9 +1238,21 @@ dependencies = [ "rand_core", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de4c2cc40e1019faac8cdbe61172c7be09960cfe240c712be46df3795c53fce8" dependencies = [ "anyhow", "bincode", @@ -1226,19 +1262,19 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de4c2cc40e1019faac8cdbe61172c7be09960cfe240c712be46df3795c53fce8" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -1249,7 +1285,7 @@ dependencies = [ "rand", "serde", "sha2 0.10.8", - "sp1-lib 1.1.0", + "sp1-lib 1.1.1", ] [[package]] diff --git a/examples/patch-testing/program/Cargo.toml b/examples/patch-testing/program/Cargo.toml index ac57d413db..a9f148c529 100644 --- a/examples/patch-testing/program/Cargo.toml +++ b/examples/patch-testing/program/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } sha2-v0-9-8 = { version = "0.9.8", package = "sha2" } # Note: Can't have sha2-v0-10-6 and v0-10-8 at the same time due to crate resolution. diff --git a/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf b/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf index 5bf87b2bff..78774e8713 100755 Binary files a/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf and b/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/patch-testing/script/Cargo.toml b/examples/patch-testing/script/Cargo.toml index 29836184d4..7fe41b0941 100644 --- a/examples/patch-testing/script/Cargo.toml +++ b/examples/patch-testing/script/Cargo.toml @@ -5,8 +5,9 @@ edition = { workspace = true } publish = false [dependencies] -sp1-core = { workspace = true, features = ["neon"] } +sp1-core-machine = { workspace = true, features = ["neon"] } +sp1-core-executor = { workspace = true } sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/patch-testing/script/build.rs b/examples/patch-testing/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/patch-testing/script/build.rs +++ b/examples/patch-testing/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/patch-testing/script/src/main.rs b/examples/patch-testing/script/src/main.rs index 5ffaa22aa1..b3bbcb677f 100644 --- a/examples/patch-testing/script/src/main.rs +++ b/examples/patch-testing/script/src/main.rs @@ -9,42 +9,47 @@ fn main() { let stdin = SP1Stdin::new(); let client = ProverClient::new(); - let (_, report) = client - .execute(PATCH_TEST_ELF, stdin) - .run() - .expect("executing failed"); + let (_, report) = client.execute(PATCH_TEST_ELF, stdin).run().expect("executing failed"); // Confirm there was at least 1 SHA_COMPUTE syscall. - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::SHA_COMPRESS)); - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::SHA_EXTEND)); + assert!( + report.syscall_counts.contains_key(&sp1_core_executor::syscalls::SyscallCode::SHA_COMPRESS) + ); + assert!( + report.syscall_counts.contains_key(&sp1_core_executor::syscalls::SyscallCode::SHA_EXTEND) + ); // Confirm there was at least 1 of each ED25519 syscall. - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::ED_ADD)); - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::ED_DECOMPRESS)); + assert!(report.syscall_counts.contains_key(&sp1_core_executor::syscalls::SyscallCode::ED_ADD)); + assert!( + report + .syscall_counts + .contains_key(&sp1_core_executor::syscalls::SyscallCode::ED_DECOMPRESS) + ); // Confirm there was at least 1 KECCAK_PERMUTE syscall. - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::KECCAK_PERMUTE)); + assert!( + report + .syscall_counts + .contains_key(&sp1_core_executor::syscalls::SyscallCode::KECCAK_PERMUTE) + ); // Confirm there was at least 1 SECP256K1_ADD, SECP256K1_DOUBLE and SECP256K1_DECOMPRESS syscall. - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::SECP256K1_ADD)); - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::SECP256K1_DOUBLE)); - assert!(report - .syscall_counts - .contains_key(&sp1_core::runtime::SyscallCode::SECP256K1_DECOMPRESS)); + assert!( + report + .syscall_counts + .contains_key(&sp1_core_executor::syscalls::SyscallCode::SECP256K1_ADD) + ); + assert!( + report + .syscall_counts + .contains_key(&sp1_core_executor::syscalls::SyscallCode::SECP256K1_DOUBLE) + ); + assert!( + report + .syscall_counts + .contains_key(&sp1_core_executor::syscalls::SyscallCode::SECP256K1_DECOMPRESS) + ); println!("Total instructions: {:?}", report.total_instruction_count()); println!("Successfully executed the program & confirmed syscalls."); diff --git a/examples/regex/program/Cargo.lock b/examples/regex/program/Cargo.lock index 503d0f9979..53116ab999 100644 --- a/examples/regex/program/Cargo.lock +++ b/examples/regex/program/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "bincode" version = "1.3.3" @@ -35,6 +41,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -60,6 +72,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.10.7" @@ -70,6 +93,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "generic-array" version = "0.14.7" @@ -91,6 +120,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -121,12 +183,45 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -212,6 +307,30 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -229,7 +348,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -243,19 +362,31 @@ dependencies = [ "digest", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -269,6 +400,17 @@ dependencies = [ "sp1-lib", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.60" @@ -280,6 +422,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -303,3 +462,12 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/examples/regex/program/Cargo.toml b/examples/regex/program/Cargo.toml index 6b01aece81..646259670d 100644 --- a/examples/regex/program/Cargo.toml +++ b/examples/regex/program/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } regex = "1.10.3" diff --git a/examples/regex/program/elf/riscv32im-succinct-zkvm-elf b/examples/regex/program/elf/riscv32im-succinct-zkvm-elf index 04c2e1e47c..5793baa3e3 100755 Binary files a/examples/regex/program/elf/riscv32im-succinct-zkvm-elf and b/examples/regex/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/regex/script/Cargo.toml b/examples/regex/script/Cargo.toml index 4efbee5cb5..b6430aacb6 100644 --- a/examples/regex/script/Cargo.toml +++ b/examples/regex/script/Cargo.toml @@ -8,4 +8,5 @@ publish = false sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } + diff --git a/examples/regex/script/build.rs b/examples/regex/script/build.rs index 32b99273cd..2e503ae98c 100644 --- a/examples/regex/script/build.rs +++ b/examples/regex/script/build.rs @@ -1,4 +1,4 @@ -use sp1_helper::build_program; +use sp1_build::build_program; fn main() { build_program("../program") diff --git a/examples/rsa/program/Cargo.lock b/examples/rsa/program/Cargo.lock index 0ab8fe064b..4cbf5f0f88 100644 --- a/examples/rsa/program/Cargo.lock +++ b/examples/rsa/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.2.0" @@ -47,6 +53,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.5.0" @@ -105,6 +117,17 @@ dependencies = [ "pem-rfc7468", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "digest" version = "0.9.0" @@ -124,6 +147,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "generic-array" version = "0.14.7" @@ -145,6 +174,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -166,6 +228,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -225,6 +293,30 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pem-rfc7468" version = "0.3.1" @@ -262,6 +354,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.81" @@ -341,6 +442,30 @@ dependencies = [ "sp1-zkvm", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -358,7 +483,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.60", ] [[package]] @@ -390,19 +515,31 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -438,6 +575,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.60" @@ -449,6 +597,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -473,6 +638,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/examples/rsa/program/Cargo.toml b/examples/rsa/program/Cargo.toml index cfb330ab48..9a9db9e814 100644 --- a/examples/rsa/program/Cargo.toml +++ b/examples/rsa/program/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } digest = "0.10.7" rand = "0.8.5" rsa = "0.6" # Check for the latest version diff --git a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf index eb6c2aae4b..2ab2c15058 100755 Binary files a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf and b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/rsa/script/Cargo.toml b/examples/rsa/script/Cargo.toml index 709cb17a55..668fd32149 100644 --- a/examples/rsa/script/Cargo.toml +++ b/examples/rsa/script/Cargo.toml @@ -9,4 +9,4 @@ rsa = "0.6" sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/rsa/script/build.rs b/examples/rsa/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/rsa/script/build.rs +++ b/examples/rsa/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/ssz-withdrawals/program/Cargo.lock b/examples/ssz-withdrawals/program/Cargo.lock index d74a4b8aa6..9c359473a1 100644 --- a/examples/ssz-withdrawals/program/Cargo.lock +++ b/examples/ssz-withdrawals/program/Cargo.lock @@ -1156,6 +1156,30 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sec1" version = "0.7.3" @@ -1310,19 +1334,31 @@ dependencies = [ "rand_core", ] +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", diff --git a/examples/ssz-withdrawals/program/Cargo.toml b/examples/ssz-withdrawals/program/Cargo.toml index 95d1f111af..5e59a6dbdb 100644 --- a/examples/ssz-withdrawals/program/Cargo.toml +++ b/examples/ssz-withdrawals/program/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } hex-literal = "0.4.1" ssz_rs = { version = "0.9.0", features = ["serde"] } serde_json = "1.0.111" diff --git a/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf b/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf index bcd6245c2b..a39c9cfd70 100755 Binary files a/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf and b/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/ssz-withdrawals/script/Cargo.toml b/examples/ssz-withdrawals/script/Cargo.toml index 50a07d7351..7f8d4cf912 100644 --- a/examples/ssz-withdrawals/script/Cargo.toml +++ b/examples/ssz-withdrawals/script/Cargo.toml @@ -8,4 +8,4 @@ publish = false sp1-sdk = { workspace = true } [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } diff --git a/examples/ssz-withdrawals/script/build.rs b/examples/ssz-withdrawals/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/ssz-withdrawals/script/build.rs +++ b/examples/ssz-withdrawals/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/tendermint/program/Cargo.lock b/examples/tendermint/program/Cargo.lock index c6c0aea2ea..9412aabb76 100644 --- a/examples/tendermint/program/Cargo.lock +++ b/examples/tendermint/program/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.3.0" @@ -47,6 +53,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.5.0" @@ -182,6 +194,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "flex-error" version = "0.4.4" @@ -279,12 +297,39 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itertools" version = "0.12.1" @@ -318,6 +363,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "num-conv" version = "0.1.0" @@ -356,6 +407,30 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "paste" version = "1.0.15" @@ -396,6 +471,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.85" @@ -482,6 +566,30 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde" version = "1.0.204" @@ -571,19 +679,31 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "sp1-lib" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "bincode", "cfg-if", + "hex", "serde", + "snowbridge-amcl", ] [[package]] name = "sp1-zkvm" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bincode", "cfg-if", @@ -750,6 +870,23 @@ dependencies = [ "time-core", ] +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "typenum" version = "1.17.0" @@ -774,6 +911,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/examples/tendermint/program/Cargo.toml b/examples/tendermint/program/Cargo.toml index e45d506e8f..6e3b9e9891 100644 --- a/examples/tendermint/program/Cargo.toml +++ b/examples/tendermint/program/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../../zkvm/entrypoint" } +sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } serde = { version = "1.0", default-features = false, features = ["derive"] } tendermint-light-client-verifier = { version = "0.35.0", default-features = false, features = [ diff --git a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf index 7e38cf4299..1b0da72ab4 100755 Binary files a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf and b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/tendermint/script/Cargo.toml b/examples/tendermint/script/Cargo.toml index 3f676e8d55..e5c6ff4ff4 100644 --- a/examples/tendermint/script/Cargo.toml +++ b/examples/tendermint/script/Cargo.toml @@ -5,7 +5,7 @@ edition = { workspace = true } publish = false [dependencies] -sp1-core = { workspace = true, features = ["neon"] } +sp1-core-machine = { workspace = true, features = ["neon"] } sp1-sdk = { workspace = true } reqwest = { version = "0.11", features = ["json"] } tokio = { version = "1", features = ["full"] } @@ -21,4 +21,7 @@ serde_cbor = "0.11.2" sha2 = "0.10.8" [build-dependencies] -sp1-helper = { workspace = true } +sp1-build = { workspace = true } + +[features] +cuda = ["sp1-sdk/cuda"] diff --git a/examples/tendermint/script/build.rs b/examples/tendermint/script/build.rs index 03388acab7..5aece05a24 100644 --- a/examples/tendermint/script/build.rs +++ b/examples/tendermint/script/build.rs @@ -1,3 +1,3 @@ fn main() { - sp1_helper::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); + sp1_build::build_program(&format!("{}/../program", env!("CARGO_MANIFEST_DIR"))); } diff --git a/examples/tendermint/script/files/block_2279100.json b/examples/tendermint/script/files/block_2279100.json new file mode 100644 index 0000000000..721d43dee1 --- /dev/null +++ b/examples/tendermint/script/files/block_2279100.json @@ -0,0 +1 @@ +{"signed_header":{"header":{"version":{"block":"11","app":"1"},"chain_id":"mocha-4","height":"2279100","time":"2024-07-16T21:21:11.200637657Z","last_block_id":{"hash":"FBD753D2965760B76EB93BD4D2DBE2C40AFCEF5EDDA3A30D1CB3F19E635C055A","parts":{"total":11,"hash":"F842D166297F1D45302286EEC86CE778939672E72B3430F5631CB9232FC04890"}},"last_commit_hash":"9C9B62C4AB6D3DE0F2E490D24DF01DB2757E310F2E255F0995B3D9050FCCD7AC","data_hash":"F52F291DCC807A1F67CE134BF750DE2627A404D517BF39B144A162090D7EF874","validators_hash":"761B52540AA384D2B2CEB9D31F1619DB75498E9EE162949E30EFE10D14BC405A","next_validators_hash":"761B52540AA384D2B2CEB9D31F1619DB75498E9EE162949E30EFE10D14BC405A","consensus_hash":"C0B6A634B72AE9687EA53B6D277A73ABA1386BA3CFC6D0F26963602F7F6FFCD6","app_hash":"A66EABEC8662632A5120D8416A44C17630C791F7CE30C5103A57B088275A2DC9","last_results_hash":"D5353DA58080C25EB981F6702C3F528C7DA60C94DADC244EF8BDF91B09DAB08B","evidence_hash":"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855","proposer_address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E"},"commit":{"height":"2279100","round":0,"block_id":{"hash":"EF3FA80FE032E291DC94CF6F9912071A319E5042F078BE98184E3C3AC9FF97E7","parts":{"total":11,"hash":"354346DE3D8F76CAFD9EFD545AB336B57A8AE6D11E59EC9334B8DFD3CCA061FF"}},"signatures":[{"block_id_flag":2,"validator_address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","timestamp":"2024-07-16T21:21:23.579267519Z","signature":"QuNKNEqfip6ErAtO5NKkr3qowViFIVx7Hx9NQC0O2bT5aFWNXwa2u83rgL2dLtkDCCPe9/Y8QLBCrEzDZfRhBg=="},{"block_id_flag":2,"validator_address":"762CBA617226A799D898F134DD12661C7F1129EB","timestamp":"2024-07-16T21:21:23.455016236Z","signature":"zAZjNGb4aB42iRZpo4qGin/SHpo/rkj+evu6cT1Qr9phlE/cWpGxbVLdaiA4egpIJCylErEA2OAYNlb7htJhDQ=="},{"block_id_flag":2,"validator_address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","timestamp":"2024-07-16T21:21:23.471749864Z","signature":"j2Tq3SvwR+h9F/5q02u7Xutw2VXz/jUasDAiMeybdO3bOmI+PEl0Xthc07UzQ4CYyk7Okv4cNRwkqUdc+iVQCQ=="},{"block_id_flag":2,"validator_address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","timestamp":"2024-07-16T21:21:23.46842993Z","signature":"8fUxhlFNlwLxpMIDVmTgkBDbfhZa95hEJxccffMo5oWF/NGYnXIBocW8rRs0MtCC2Aa6yYY4Y6rggUhT7WvuDQ=="},{"block_id_flag":2,"validator_address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","timestamp":"2024-07-16T21:21:23.16428668Z","signature":"Ro709XYYsikmZ9V8XkXmoMbcrbsqajxuFWzpd+jdHqCCCTEGBlHOtMjIi4J7h1qJP58GMOLsfyB5wmizKbuKBQ=="},{"block_id_flag":2,"validator_address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","timestamp":"2024-07-16T21:21:23.537756988Z","signature":"qFP6owZcxA0b1wq1WbaeTtRgXzbjQn9ugiAcpAT6gaaoageXAqN2NUfxXmE0hbo4OIURj2HQZdjO0mg35CQOCw=="},{"block_id_flag":2,"validator_address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","timestamp":"2024-07-16T21:21:23.464472161Z","signature":"L8VjUL/6+rZtS76oz7+Lddi3DaOlUJVnYrIffYcrRf4RPmz7AN0w3wPHk6YEovn+zFm1AVNM5fJX2NoVHS3eCw=="},{"block_id_flag":2,"validator_address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","timestamp":"2024-07-16T21:21:23.476167081Z","signature":"2UutyARhwy2LqSUooiI/e2ZQxsmMGSm8+CvzaVFt7rbfyVlGfsF2b+mgD7TqXKSDOn4FFXtlSGOn/OxWglI4AQ=="},{"block_id_flag":2,"validator_address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","timestamp":"2024-07-16T21:21:23.561794959Z","signature":"4sWtWQH3d/IAExjkHMauqfLafsd2J7IusxQk2dVq/hstJNtidwIAx6nYOpBAYCTPDl0SVicYGclUbgJxcsWrDg=="},{"block_id_flag":2,"validator_address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","timestamp":"2024-07-16T21:21:23.528527525Z","signature":"sK7AHBVJdoyUhhh0oKTtCg9RTDoOhLB4cQpUoT+0wHqP2gUL8bwEmN5cxGQda0Vf1T2kOQBFmrHZEzVRxLS0BQ=="},{"block_id_flag":2,"validator_address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","timestamp":"2024-07-16T21:21:23.530668252Z","signature":"2cePxvPUU30Tkz46CkExrGklJFyHHf1ImxfnvFC9KI4qey9eIOqkkTi1wfesZ5uPpU/EUatdJnIYqsomqrnECw=="},{"block_id_flag":2,"validator_address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","timestamp":"2024-07-16T21:21:23.516304185Z","signature":"NcpoI9JqnXyOUFaK6C0k5Ycvd7NhX1QRyJSUroJKCHUa2olCBOF9oAUazSnbQwS7276QfRP7P8qCnsq79P2iDg=="},{"block_id_flag":2,"validator_address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","timestamp":"2024-07-16T21:21:23.823864119Z","signature":"4+dFRDOMyHAtNjH1d8aNbzFOwjWi5gxinKR1ST+Wt1ztfVCORVpijNj8NAJ7UrLJDqfCzfP708H+uJ2vQEORAQ=="},{"block_id_flag":2,"validator_address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","timestamp":"2024-07-16T21:21:23.634950974Z","signature":"/iTorIxinKMccWIWt8uNtrMJV24zZlb+nvJIfBrxG5l4SEfnM0LchpK8SycRMd5yvh/uhTUJ8sZ09VTgyzV8Cw=="},{"block_id_flag":2,"validator_address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","timestamp":"2024-07-16T21:21:23.474688335Z","signature":"G32ovKXT2sPw0WvhYvXqlI1G3GHE1kY3dphK48olnnAfR2Dtp25sFQTyCLh2E5+yxFl5Pxvjx8dWs+ZkFZuHDA=="},{"block_id_flag":2,"validator_address":"9079C978817165244C051EFCE5AD163AAA905C6F","timestamp":"2024-07-16T21:21:23.47184029Z","signature":"Q/IXyPZZSdTo/gqnIkNfwNs8PPhujaeXpJKf00ep5ohKGcHmAH4hS0C25NIn6wFlXo0wWNW/9DxCivBBgFY1CQ=="},{"block_id_flag":2,"validator_address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","timestamp":"2024-07-16T21:21:23.92793085Z","signature":"RzthPealyMuYfnjc+ygyg1x6YOYrOVQlKvB6ucPLnsPK24P6km8dpoj5tds6DGTeJ9q3fwpHeLX7fOQ46cW2AA=="},{"block_id_flag":2,"validator_address":"11637B088406D4F3EFF52F2230C8068D230C7611","timestamp":"2024-07-16T21:21:23.540841956Z","signature":"5uSWAY4fbey9Nc8al6Y03e/oSpQ0U8e919Ws7QkmWJxARFVZpoMtV2fn3LaO6Aj4+WjCJk63VrsQYX0dJhy1CA=="},{"block_id_flag":2,"validator_address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","timestamp":"2024-07-16T21:21:23.5279986Z","signature":"v1P9WNSLXw4qu3U7r7fmaCYVV3MGRqGcSlPcPEbc0OI6w5SZ+aJkop4JleLwnB85nw23imhYYZr5mA5q6kDaDg=="},{"block_id_flag":2,"validator_address":"BB408FA902A7B6A938C788957B2A874153261EC5","timestamp":"2024-07-16T21:21:23.50745286Z","signature":"R9YS+NuQo9xwPGzZi08VvWK/+Sc0klAwFQ5NoZlLsoaKaH/DN5dYtewyns2Ntckj6+4XdmTZkhRbBPz7++HGDA=="},{"block_id_flag":2,"validator_address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","timestamp":"2024-07-16T21:21:24.34806458Z","signature":"G8M/13/DGebx2ysxm1M1r5yL06VaLJwuBeyv98RXicmkna946fMl5X0Vhg5L2QW2AWU7OqzzOu3HXOfcZuNdBA=="},{"block_id_flag":2,"validator_address":"F005689992F73B55B537461AC0AE0DF9694B36CF","timestamp":"2024-07-16T21:21:23.680163408Z","signature":"qvppGRrkSGOSpyAdqcLCCg7HuBuWsqqDurPEfdjG9Mtk/4gn5BO5tucJJR2sZccCXq2MgY5dJe2v/F9f3xsJBA=="},{"block_id_flag":2,"validator_address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","timestamp":"2024-07-16T21:21:23.846054841Z","signature":"FTKKm2xLIxnJduGME1mA4pEZPQOnrKKQeVgsZ7f3RC93wUN6u3pUESRbPBowMysRdLKM0bh8qsdBwt0EkAMiAw=="},{"block_id_flag":2,"validator_address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","timestamp":"2024-07-16T21:21:23.718839237Z","signature":"zVbTVeE6u+G1CGGjQyisdIikqu1DW37ffSxN4dd3Ph2SPXXASNRNsSYpTVNAKfthymNOytokwAV2uFLH4SPtDg=="},{"block_id_flag":2,"validator_address":"98271A1B3690F4EC867C760DBCA3754684F485AC","timestamp":"2024-07-16T21:21:23.513090303Z","signature":"2dS+WiOIfsaZAdoJcgz7n77y2V9GmuyjJV1pUqzWRdwu5WVKCxKWpAK4toP3Z2D3pyAJ40inwf0IljC2nlfgAQ=="},{"block_id_flag":2,"validator_address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","timestamp":"2024-07-16T21:21:23.503530235Z","signature":"LJJAKRUO1Hex7aELqyjmCPWoRLN0H3zk1FGH6Y2xk4yscqGXInAX3FxKflRXTZ0p0ax+WWZmnvlU3ZaipSMvCw=="},{"block_id_flag":2,"validator_address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","timestamp":"2024-07-16T21:21:23.851965372Z","signature":"nEz+oKZ/CXBCcizFuUEnu83zrkd/vUax8gVKDtDS0mHeAFUjXR/psu5ltk671c71I80W4W41wvfcNiVemp3KBA=="},{"block_id_flag":2,"validator_address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","timestamp":"2024-07-16T21:21:23.505513775Z","signature":"1QhJoqmtDT6X/qpHWuU/qHwBc9mxu/AZrZRZHWYPo6R5MeWsToVCt7L2+ZopT8rpPhjAq0YlYwjQZ6EKTjLeBQ=="},{"block_id_flag":2,"validator_address":"28B6061D5E269B3585F019E1748E32CA9F34E739","timestamp":"2024-07-16T21:21:23.838542171Z","signature":"eFLe7+x+4MsosddknriNdGRY+JGfZP3HMZVOfIQ3qZHSPovt5+dBAyZcUH6b1fvuS8lOSqqAOESXHEO5gzLyBg=="},{"block_id_flag":2,"validator_address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","timestamp":"2024-07-16T21:21:23.426821803Z","signature":"rR/Uwy1HzdhVE9KqTj5TlK1zFOho+zmUAWjS6IPlGyK/gvQjZU3svGAcriCvUm5cYDGs4GGEJoA7rEgytYlqBA=="},{"block_id_flag":2,"validator_address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","timestamp":"2024-07-16T21:21:23.852693409Z","signature":"0jgYzIyUMZDc25zeQ8nDhCcJtN2OQCjCCO/MFiPBRo6cNHn5mbXJPdWKn6c1fz1lZR1AAMSIyfvQCf7gw68cBg=="},{"block_id_flag":2,"validator_address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","timestamp":"2024-07-16T21:21:23.658016044Z","signature":"spDtXNYJdR1862NKeCtWqAugxfvJ7+KZCQMt82Z8wPGF+xBKEULm6s1OorNLzz5f4qzzN/QQOY4y7wGPiVi6Ag=="},{"block_id_flag":2,"validator_address":"0DC59C626E4753D889DE2D3262A9A613E754668A","timestamp":"2024-07-16T21:21:23.540652438Z","signature":"hAe29yKwWXTPAVguWsoRgCZ3jLJLa5YqwaxqOp6N3b9xEmFUDR02YL5ACeoIC5ZmGfa19B1XOgXgluw1wp3qAQ=="},{"block_id_flag":2,"validator_address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","timestamp":"2024-07-16T21:21:23.576459403Z","signature":"XZMiVqN8N5B8sqI6IYmWHc8rHfzZA7axW/Lxuu1kysyIi17PO+NTATRs/aUDq8m4vqgXJrZJ2X4/Opo+sukEDg=="},{"block_id_flag":2,"validator_address":"346001263089D83465A72C6DB5EFBC32359111A3","timestamp":"2024-07-16T21:21:23.461801905Z","signature":"BM4E1zFKZC260NZqEDSgAXu6qvbdVKbk/0XME+GMaKZFCcj5yfbp8lGQoqZD8m905eYtlVlFWTEVpw/KYHzGAw=="},{"block_id_flag":2,"validator_address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","timestamp":"2024-07-16T21:21:23.51943268Z","signature":"y74YdG/Co/xDxyGhVG7BM+nwS5f09jOOes/q4zhCPx8lnhplR/2C5UMWTAjmUpLbfXCHYMhlbhJF+7uoqaCfDg=="},{"block_id_flag":2,"validator_address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","timestamp":"2024-07-16T21:21:23.537635719Z","signature":"KKDf5Zr64bOUrFWHxJicD4tYrMtDvoqGRcghWLZtn8cKrjjoH5qnLw+l3Lrk+Ek3Wd7QW9ikmVe/1wyKwaKBAA=="},{"block_id_flag":2,"validator_address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","timestamp":"2024-07-16T21:21:23.767483941Z","signature":"pgtqx3hN4KUR//JRC5iRyEKZaA6IOVbSgypodSify9oPR4Zi+RVEj1JGRg8om+1ri6sf007dbn8iZ/ynYcoyBA=="},{"block_id_flag":2,"validator_address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","timestamp":"2024-07-16T21:21:23.474144535Z","signature":"OHAFO/d2Di65F40/Pqecux3Z14VfsuKTdeTI3MDJSNFz0rVHZDaxHnP5xXI8TtZVhKgwGd2twqyRa+6Y1OLwBg=="},{"block_id_flag":2,"validator_address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","timestamp":"2024-07-16T21:21:23.563890574Z","signature":"AGLrJ9QCDT0lxwgpEAwvBdjZxX5spPSKCTglgMXtWyjhbQ7ZeTZHhb4qo+bh4m+m2wIHxWrgQRu1wpRaawvoCQ=="},{"block_id_flag":2,"validator_address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","timestamp":"2024-07-16T21:21:23.546958701Z","signature":"TUQF7E4iLXQOJn0neHL1btJ24TzX0fIJOj558+THXwVO6a2RwbAHTxrV/U8OSe8wXODyBDDRIjO32uITmUC2Ag=="},{"block_id_flag":2,"validator_address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","timestamp":"2024-07-16T21:21:23.614438913Z","signature":"ayKmKh+/QKdQZRyGFkbLXX2tp2W5LqsvPNC4mWp16GbMVBp4Fs7fGpFN3WfLvPwxllw3PhoWSD5TkxT/kW6nDA=="},{"block_id_flag":2,"validator_address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","timestamp":"2024-07-16T21:21:23.474611393Z","signature":"nB8VYOQNSxP61vmYkPDzENV0WybBUbYnj3g/HjXO5wLBybqkRtQiNMYnBy8Cizay8ZlG4qBUJ0bVrd8i6eQ4Ag=="},{"block_id_flag":2,"validator_address":"E309A8AFFF70D04126D04BB53071B6020580D104","timestamp":"2024-07-16T21:21:23.765986078Z","signature":"uLPBDKncUkTWK1WJ4PBio7nXoqB70v4rWOOozGZG/WdyHXRHSfTpPkmiJb6CEtfQuFB4UMdbI96CpbUNWJbkAg=="},{"block_id_flag":2,"validator_address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","timestamp":"2024-07-16T21:21:24.003360149Z","signature":"LBRwtTw9Wh5sWRvDSnORt3xGlTuqux1omxV3v53IjeWrt3YzolFFy13Xiw9xq6lj+oHAeAxOnZpXH/AxKT3SBg=="},{"block_id_flag":2,"validator_address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","timestamp":"2024-07-16T21:21:23.793308637Z","signature":"fVjDE9nGS+3DpojDDfFt0wLVn7M783M7c8dmOEmlW+qGTAzvZBn5W+acCLI2Al4bvufvqkHLYAZNXke1yHUwAg=="},{"block_id_flag":2,"validator_address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","timestamp":"2024-07-16T21:21:23.565598211Z","signature":"Znhj7sBinOE/JpHE3rI2zvKtTteBP7V42mVqvW8gHhZyUqkNEcbTsKYKgoVxloYOPN+I71GrQThJzomvHywqBg=="},{"block_id_flag":2,"validator_address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","timestamp":"2024-07-16T21:21:23.430017624Z","signature":"OeW4vJAF1RqshsjY87Jvjhk0lbDdKkMrJ8+hxOb7tWO9xUG1fF1V2jgPOVCkZHhtTaUmltJXTD03V9MZEvHIBA=="},{"block_id_flag":2,"validator_address":"88731522401F260D5C253222CF6EF71586A192D3","timestamp":"2024-07-16T21:21:23.485033667Z","signature":"TOqAysFwmBJ7oiSWJn7ZhKT4OGYd+tlejnCARy8KrhAk1v1f/MuYu/8tHxvJ1HkWhOhxx3agBBbwAWZ18tXYAQ=="},{"block_id_flag":2,"validator_address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","timestamp":"2024-07-16T21:21:23.503845049Z","signature":"xYADEJDZ/MPwf/LMv4f1eYsdtN89k+n+8kU84w13ORyNJVOU24ZT2wTzQ+wfLTxCL0+qjEspmJIyZ0/pRy33AA=="},{"block_id_flag":2,"validator_address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","timestamp":"2024-07-16T21:21:23.806466666Z","signature":"r8iW5WbqERDo72kTuJNMSpXR3sRHi8YKSqMhaG191awvq1irVOsS5k7k6LVnYsP0psk6wBJSm0LoBCYHH8kTCw=="},{"block_id_flag":2,"validator_address":"5769499735A69F335467D419764A69FAFFE29607","timestamp":"2024-07-16T21:21:23.596707071Z","signature":"nhGT8rTsnRJLlzirYL02egruMZEEPZFJn4DZ1gG5o3G0msQHOfjib5y0HygZ4b5GKNBw1ZCRysXzJOF+GakECA=="},{"block_id_flag":2,"validator_address":"113388853F11E28044A4ED3B11DF745D00D709CD","timestamp":"2024-07-16T21:21:23.526604703Z","signature":"W9/nYv9mgtcr3VVwBqFyk3GkPh+ill+Xj6I5bWQj0S0rFMA4qpPYPd5RhzLeVwoWM5UC0s0s55r7o4f+wL5lBg=="},{"block_id_flag":2,"validator_address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","timestamp":"2024-07-16T21:21:23.653963489Z","signature":"25M6sGaVGk7XKRyZqdzCWV1qlmkYPlBC7et1pXGcfDrQ7StrQXFAEW1ThjLi2bwZmfSsxQ8jVrVX1ap58KYZBQ=="},{"block_id_flag":2,"validator_address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","timestamp":"2024-07-16T21:21:23.530224992Z","signature":"2GBLidODTwViYh925W8ZiHfXMx3TbQauO6/rHysdOZl8va0nEzD433VoBNk/Bf44fNgJ+xJeVvDbdO25FGdPAA=="},{"block_id_flag":2,"validator_address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","timestamp":"2024-07-16T21:21:23.643383029Z","signature":"4InDpW5RLvvpgweORc8eI/o15qPA06y7M8oRt2GhFa92MhT613/n5K6/bmD2NiWoDcenHauelgQB7iTCGukSDQ=="},{"block_id_flag":2,"validator_address":"924090B949A3A3A43AEE52C4DAE342332C57B684","timestamp":"2024-07-16T21:21:23.782023666Z","signature":"H3VpMn2KUix1v27wcpB+V5ygvDfPRJ8wo9k2pSIPpQQRUEKX9boRrN9UC/ciGTA2VxK9g7D+3ojWv8jnQNgDDA=="},{"block_id_flag":2,"validator_address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","timestamp":"2024-07-16T21:21:23.504651498Z","signature":"NVBGneFLhhgrudyf7Mf3Qd74urlIoWcqVx7ckzA8+YNa+JxqqJgzyDBsHpGdIef+RUHtcYjs4cdEthBtgl6hCg=="},{"block_id_flag":2,"validator_address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","timestamp":"2024-07-16T21:21:23.494596959Z","signature":"IGB1dqgIqZTFQRXeF/AcnCu4fzvjrhvEwTayUILRc9WvTbmd1PFfNDtYDlXTL4hsYQkAfu6ELl5PF5T+EUAaDQ=="},{"block_id_flag":2,"validator_address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","timestamp":"2024-07-16T21:21:23.608258079Z","signature":"PcGK6TOeNGSlB8jYh0m9eMM7pTW1ztsplLXkLrwo/2O1p0WZ0uHceo0NT7hNhqwbH38BxWo5UgmNlT1U/dWzCQ=="},{"block_id_flag":2,"validator_address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","timestamp":"2024-07-16T21:21:23.624828672Z","signature":"ePgY6GPnHPZ8g4+ne8NQpaMPl/ri7lmPv8i5h2fopewOerQugHGcl8Efjf0Xl3IY1179PxrWZ+1ukDjZ31KnDg=="},{"block_id_flag":2,"validator_address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","timestamp":"2024-07-16T21:21:23.482581757Z","signature":"RTFTn6TtmUm4Fd+N6vn+L7g3vJqfpBHzxn7QJy8E0Yv+NgRxXToTAOClLRxndH+KHJsomowu5xo7nzq2qzYHAw=="},{"block_id_flag":2,"validator_address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","timestamp":"2024-07-16T21:21:23.566793176Z","signature":"x+J5juTAUYhpSypajf2usKWIVDS4DgcRiDznuIm9ZuqD8CtviZviuWKVGJ+asLj/MmtbfEhrrvfEecXDNquVBw=="},{"block_id_flag":2,"validator_address":"D5CABF35D9C01401B32540F938BE59FA2B044067","timestamp":"2024-07-16T21:21:23.499983379Z","signature":"1+Z6QhgD0303gW4zmHLnLklD6ClynSb4upPMUn0EUSIABReRjK1Rj9y98wWnmc3qheS9SK+WkpOluUFwcCqzAg=="},{"block_id_flag":2,"validator_address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","timestamp":"2024-07-16T21:21:23.49133422Z","signature":"xRue/YvO+ZLuGJj+UEBk0Q7B3t/+uUgszC76yffYn4ff83fQ2fTSYzKN5SCknJCEtQ7tir2sELVPx/GrrsqEBw=="},{"block_id_flag":2,"validator_address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","timestamp":"2024-07-16T21:21:23.602214615Z","signature":"V7qvwXHir854JYWJso6S1fH212YNuQzhQIyuWY7pncFpoURIBdLxwQBRzVyAxim8Nt+YXvOSf+NUuznO1T2FBA=="},{"block_id_flag":2,"validator_address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","timestamp":"2024-07-16T21:21:23.466592821Z","signature":"BWM5b/UVD3OXlkQf69Vu8tkG6YjpV7Pjjoo8Cv+VMFGNGD/bRaNI0ykJ4SJhNQ0ajexFyUUdsuIbwNuyH1WxBw=="},{"block_id_flag":2,"validator_address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","timestamp":"2024-07-16T21:21:23.762983695Z","signature":"JLY9gcz1vr9QWJKDbLyBO3+hB/0xgl/wBTqqzOzHTaJ9c18/R3v04iiidmaxt7tRST8MzfNHQ/ivdKveUnCZAw=="},{"block_id_flag":2,"validator_address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","timestamp":"2024-07-16T21:21:23.473640117Z","signature":"Es09yGUBUs3xf28ba8pNTIroR4zdsmaJHOuBu5VEuIQFdDcwn3cI76KjwpweB9KKCe2D3iL6u3QmbIeQ+KCFCw=="},{"block_id_flag":2,"validator_address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","timestamp":"2024-07-16T21:21:23.495210694Z","signature":"v1zMMCdZOQxrp81ImEQGj3NCuFng4J2AYlEPIvbaDr638jX6ICRjeLTLWBjxcJKQB5JDAGQ9aZZpBAkgSO4/BA=="},{"block_id_flag":2,"validator_address":"E5183117268691950E77D53340C23857662CC908","timestamp":"2024-07-16T21:21:23.522131619Z","signature":"f+XTlcytLgF5XNswoXeCyVns5Gn7AoTZHntpRzZ7nQJ5zSVzXrrq1XKIq1K5X1TgWZvdiA49n4nX0Dd0FwF7DQ=="},{"block_id_flag":2,"validator_address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","timestamp":"2024-07-16T21:21:23.682617846Z","signature":"6DeHBhT9dXktRnTX7YzY8qdOrC95yUO5izzIRx3T1rTHh9SEeOy0trAn3/r3TarwQmYaO/yOAIpmlagjf3TgDQ=="},{"block_id_flag":3,"validator_address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","timestamp":"2024-07-16T21:21:23.900381101Z","signature":"0TwlMp2oBby+IBmFeT4O/FCwSoGCeFWne8plBlxKBSggCGKT8pstEKoOYGYHC6ZP0458998JY67HMTMiZpgPBw=="},{"block_id_flag":2,"validator_address":"633744F3BE877E6DF590E72E99425BA653156B93","timestamp":"2024-07-16T21:21:23.534458433Z","signature":"DZcJiZ1oBGiXcHE8z5xEfyuV7sp9Nn8m0tku/UigTx8tASWejhBC/izT6P+1OwjlL/9nWlqTY9hoDc4Y/oFyBQ=="},{"block_id_flag":2,"validator_address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","timestamp":"2024-07-16T21:21:23.487169737Z","signature":"G2y0UmDJdGL+mPfE/emshN1cp1/auCpEQ6YcwcUMlvIqDl888qbT1T/9s7N36ukWmDTY+K3lo/SL4jSfZppfCA=="},{"block_id_flag":2,"validator_address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","timestamp":"2024-07-16T21:21:23.962492904Z","signature":"gTNyTYjhaCYmHy3a52VtNojj8JdzprBEjllLLdU5l8a8VC+LTYs7e/9gaLb47BJQEnor6bfUODA6FSydfrs4BA=="},{"block_id_flag":2,"validator_address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","timestamp":"2024-07-16T21:21:23.530157162Z","signature":"DMVTh/LZvlE1E8hVBseOcKXgbeX/YGzSQQgB9DcJD9tVi9pAFr63z4HPuOXQp3FhxL8n8pGC7ra++y8SPcfMDg=="},{"block_id_flag":2,"validator_address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","timestamp":"2024-07-16T21:21:23.543027881Z","signature":"F/ALX4haTI2vxKgznLdKNbDBHh3EBwr4f3i9/lBaH3YQ72Cn7UQgxBeXAC5mdkgJrG8QLUIeiSDmCAjgDDvpAA=="},{"block_id_flag":2,"validator_address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","timestamp":"2024-07-16T21:21:23.644484055Z","signature":"5+/7MfCqc+Xk2zcvVX2Q73mRCzjfa6LfdJeOyxO7mzVp+/0oFivANHZ26hW5hTZ5IPYQ9aY9qD9t9pGsxROUAA=="},{"block_id_flag":2,"validator_address":"4A3918A6D02D25290B243A86618071374FADD87B","timestamp":"2024-07-16T21:21:23.552128685Z","signature":"aeDT3IfEpCvFhvK34uPN8tbnjljGOD7X2diFWN/R1ZwVpxZo15SMj12icUumWQ8sfAbOsha2Ba4qTZQgiaVEBQ=="},{"block_id_flag":2,"validator_address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","timestamp":"2024-07-16T21:21:23.475724448Z","signature":"d6qBlfJ0hmtTbB+eTwJPPV1MyQ4gwY5g0vpsphVqzRpk0ZJBL6y77p3IOPslJ0JM73EOJls5t9/UM0HbkHkoDw=="},{"block_id_flag":2,"validator_address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","timestamp":"2024-07-16T21:21:23.866761725Z","signature":"apiDIQUTr7cxQl0t523ZVT4WwhJtVF55YVY52rk46yrw1p5km2FFODtOrioBBEhD+YC5i0j22+Emm/NPVehtBQ=="},{"block_id_flag":2,"validator_address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","timestamp":"2024-07-16T21:21:23.686982268Z","signature":"gQt19YMAQ4T57T/XMO6WXQYdxBIPpadv7hcPYaTCG28YLAezYQTvZjNpIg94PIHIqUwQx3XjgpElydZNeny7Dw=="},{"block_id_flag":2,"validator_address":"2131A959A819C085AFA86E560D5EC0DF1D632827","timestamp":"2024-07-16T21:21:23.553923065Z","signature":"lAxXd4WNPzlO5Sm1DRDvAG33Sqj6EgfC0JRSWOJ4LVo2RzrpjqXd7/RaOphUTJlKUfWAkLfts+noI1qvGTcIAg=="},{"block_id_flag":2,"validator_address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","timestamp":"2024-07-16T21:21:23.495858321Z","signature":"XPoMNk+Lb9d1FvSN75eLk3A3uHWqSwLr7wLG/SYkBNoaCldTceFgDCXfTA27ef2aIlTIdlc6zVnkJIPRUSJnAg=="},{"block_id_flag":2,"validator_address":"F7A4EEF357935737058F08804DE4DD03144E960D","timestamp":"2024-07-16T21:21:23.479350085Z","signature":"HeW7CilLMMEf2at/SUkmW0KG7RaNEPrrGPbTw1uJJSmC6OnNt3HsOEtcKgVFyFHbUyjuz1CKB1kdoxYKwWMRCA=="},{"block_id_flag":2,"validator_address":"0A957E96258B8BC5669C9A4DA146532C93E99242","timestamp":"2024-07-16T21:21:23.79076978Z","signature":"i6tLjkMNa9kikT2WcM8K/KNSouT6JZaWGAkazVOMcGzCApoXgc7nF5oHyMr6xM7QHqqZF/tkwosTF4xINYSrBA=="},{"block_id_flag":2,"validator_address":"B07503589534AAAAD60836B33245410AD11CCEB9","timestamp":"2024-07-16T21:21:23.65602061Z","signature":"imFwlNQXMHTNaZLnIdCrCgN767MAtVuvMoCOCZ3deQYhBSyRvybZDM5zhJ0/MGMEjgQpYS8xFMFnSvRML/FEAQ=="},{"block_id_flag":2,"validator_address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","timestamp":"2024-07-16T21:21:23.546505693Z","signature":"sySj9zZRD0YPBD+DOFDNWOYXWfNeOiW4uHNliKS7mW1+5SdeOOj+Q+41IENj9rd/Yld84wJRUHuuTT1DszczDw=="},{"block_id_flag":2,"validator_address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","timestamp":"2024-07-16T21:21:23.57225231Z","signature":"gMMLwYuo+cEhTsuy6Jr7zjIO48qePdVkbJae0zbAQjiQA43msZgEpflmKwKmsIpvvL59MjNvp5sORLor7tq7BA=="},{"block_id_flag":2,"validator_address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","timestamp":"2024-07-16T21:21:23.550171448Z","signature":"VApuEhFtVuArCQyKtjY+3eJk1IR/DOOucKYyexxYhWl1RSTtJL1tn8yRWneQgHLeg87e7DOnDroZ+MnhM1a0AA=="},{"block_id_flag":2,"validator_address":"F6D5482C2405A9844A1EB215148387AD18800D32","timestamp":"2024-07-16T21:21:23.46663226Z","signature":"6KiyP5lhzbAeFbuPt2BSN5isE7QmWmmKHwON5fBbyZXVWROjHQ90XqcwQ1nVViHbQabDglF3BiS/TBVMSTfcBg=="},{"block_id_flag":2,"validator_address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","timestamp":"2024-07-16T21:21:24.019767633Z","signature":"MlKSa/fXWDSg0ObIaGp4OOcpz0sMJQaSNf5jE7OiGWqaeLVlwUNRUtJiwqIpmcL6NtlUqLIvhmzN8MjKj1oHAA=="},{"block_id_flag":2,"validator_address":"50922F9E58F64B3A219887F67117E4CF714AF490","timestamp":"2024-07-16T21:21:23.466652407Z","signature":"XInaT+nc5FsCDNTzjlnsk8sPm1MtbKO8Iv4dhutlM94CS2m50Q6FTk2iWtqZSbSKZNm0CNhb1DevjMzLcLABDw=="},{"block_id_flag":2,"validator_address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","timestamp":"2024-07-16T21:21:23.550851357Z","signature":"rlvtZrzBApdAZlFc1cQf48k7KIb/8UUFFsRnW9kRMcZ0AlBIVUQ+iyNfnfpDJvm680raPoJR3ZnY2oMgnM6UAg=="},{"block_id_flag":2,"validator_address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","timestamp":"2024-07-16T21:21:23.929327157Z","signature":"Z5rvX5lRdrZCE+0Oir3FkmORVE+4WxE0cazsxehXeTHSjZjYbLG4rMCzegoX7DMbdz8c6L2yhDCSl4nD6lwFBg=="},{"block_id_flag":2,"validator_address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","timestamp":"2024-07-16T21:21:23.747233709Z","signature":"LcVTXYZdEv39zG8F0hHi1xZf1DAycVJEEv+bL9ixiI6NFYUDetmMe90DvNp3QxaxMFbHHuEXNgtAkiODArQ+Aw=="},{"block_id_flag":2,"validator_address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","timestamp":"2024-07-16T21:21:23.537726306Z","signature":"Ze29TRdLmkbwYXyF4M1kC7KYtm86fPKkOGTS7snwN1A1y8kxgsKKRjsZbyAnxklkpiXOt2GTBFbyFkmA/cyfAw=="},{"block_id_flag":2,"validator_address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","timestamp":"2024-07-16T21:21:23.476270783Z","signature":"jE2WU0Y6XAf0MXuNu0SqKbWEVyHrh00awsGb1hAaDZkThiNPwIru+7Stwd+dHQN6yOLCPyFuBXSleiHWNiQDBA=="},{"block_id_flag":2,"validator_address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","timestamp":"2024-07-16T21:21:23.465283956Z","signature":"JdK7aEhrEybBCxGZlmK2GHyYwFSbziGV67TplKP8Gt7wyH3AKU1TJDnDFffcMfSIOzvO4eUgq+FvK/6kEvgsBw=="}]}},"validator_set":{"validators":[{"address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"l/qNaf4JDxnhP+6Pf+2OSAJYksSIkjyefYCDvZPoahA="},"power":"74052443","name":null},{"address":"762CBA617226A799D898F134DD12661C7F1129EB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE="},"power":"70555622","name":null},{"address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","pub_key":{"type":"tendermint/PubKeyEd25519","value":"njq3L6yQabWMjmh9QjBobp2XOdNytaLPoxFgY2Qd3i8="},"power":"64650439","name":null},{"address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","pub_key":{"type":"tendermint/PubKeyEd25519","value":"259mAZKhNLksTkJ7qJZf+ZreaPMQtBY7NDeslqPRa9o="},"power":"28001060","name":null},{"address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J8wAKpZrD9kRbewJDMLQAuYkYNh33PhCg+wcdVcGxIw="},"power":"27553991","name":null},{"address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D3wP4IWMZcMt9UHVzFP2J19FDCP/732nvtT/f3CIatQ="},"power":"25298561","name":null},{"address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"2XKroLDmwSjW8Z0ZadGF/Co/6Bo5OreNldOxj9fl/Ww="},"power":"25000168","name":null},{"address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3rvnDucNb0+ZSdhfQSzjdFSFiZWUGerlEt4hp1EyHKM="},"power":"25000019","name":null},{"address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","pub_key":{"type":"tendermint/PubKeyEd25519","value":"UEKnFx4sn4K1aIPxrCu4zE3+Vr4vMGgIeu2iFAQsUH8="},"power":"24714090","name":null},{"address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"i/Zow0IiKpVFWRNxOwN+Fqe9zVj9VY+Pn8+YsuSo9/E="},"power":"4066863","name":null},{"address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"B6H09N1cxmSXGgqTuAIphe7ESJsCj687/8CYiKBTh4w="},"power":"4050758","name":null},{"address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4TpozS4FflJmfBg3MYhLw12UeVUSELod0fdnX4tAQgs="},"power":"4048910","name":null},{"address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LSpewjhpxXBs00/L2L6DQJabXcSoTzmjqZNTIw5DSCg="},"power":"4048857","name":null},{"address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"SfFXATPCbIeRUsb9RP+BfdYOH0v7H2aGbPGx1HlR1I0="},"power":"4030218","name":null},{"address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5QOLCS5zoZZGk7ZXnaU883fSQAhwneIvP98XcjOte8="},"power":"4023467","name":null},{"address":"9079C978817165244C051EFCE5AD163AAA905C6F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"fODnMY6gDPpnDlAsSQ2b6M5u3gjYNaKq1JL6LBFShzM="},"power":"4009700","name":null},{"address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jqBYsfBjFJhudulObGgaMawaeccpj+21nfs+Px6oNIY="},"power":"4002311","name":null},{"address":"11637B088406D4F3EFF52F2230C8068D230C7611","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gcI3uuOTA3ZAVCMsLawhjUt7cZc/EBJeipq9XGavEsg="},"power":"4002024","name":null},{"address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wdZ6voJ0Kdh/iJvnzjS9oAiSRtr7A2S4mifU3xFfEXk="},"power":"4001100","name":null},{"address":"BB408FA902A7B6A938C788957B2A874153261EC5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7rE47Ol0HqaZhnQQqlx5BD8rNGv6yTcRQANXtMY7y4g="},"power":"4001076","name":null},{"address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zj5o33wP8tFPM8qgoC4upsLQvrAc/DGT2J4JG+LhOJ4="},"power":"4001057","name":null},{"address":"F005689992F73B55B537461AC0AE0DF9694B36CF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"KgescyXaO/6YrE/GIuqmFdP0xXTqHUflMAH40HDm/20="},"power":"4000714","name":null},{"address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LKwKvQPVTwxwW4UDpyIvGW8Sa9sUdaxhhhVdOigrEyA="},"power":"4000566","name":null},{"address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ony9i2cN/h1wawOv0WN6Ql/9lDjDeLgOVCl1fRtuyDI="},"power":"4000504","name":null},{"address":"98271A1B3690F4EC867C760DBCA3754684F485AC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"k3zGTt9YVhopwi6iL+f/XYSj7cZRT+fcPlpwsojLsvg="},"power":"4000472","name":null},{"address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"feFjsaWtjmxYp6N+1r/9Lnd4o29skxSJclmebnk49Ao="},"power":"4000469","name":null},{"address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1QMroz50WA8c/IREfyr7Mm8S75gRCfuk0Ea4fokb4E="},"power":"4000103","name":null},{"address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ps6HB6/GSvuY4fKaszGLXMdHVk38ASzBcGBXeVVeDMo="},"power":"4000028","name":null},{"address":"28B6061D5E269B3585F019E1748E32CA9F34E739","pub_key":{"type":"tendermint/PubKeyEd25519","value":"CIc6ZcjHkdfYEzQqwXZBlYVTl13ZxAinYLLgHszHVgY="},"power":"4000012","name":null},{"address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"OKWb9Bw4pE6tfYtZiigi7A8ecGnCVBiJt2h1P7o1a7U="},"power":"4000008","name":null},{"address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jjLleXjmBwA66V5gejueapJUSYqb5W+oYSGXy/QLEQk="},"power":"4000007","name":null},{"address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RYrMwDTpJWv67sFVwKtmS+UxlN7hljKGWJqOsutcB1s="},"power":"3991125","name":null},{"address":"0DC59C626E4753D889DE2D3262A9A613E754668A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"1UlN1J5cR4XlFifpA8IA7A+xa3NQ1sJ/1IhssJQ+xEM="},"power":"3961059","name":null},{"address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ueUh8xh/b1zlBcCgblxHrZ9impMwKOkgyG5P3f1HkjE="},"power":"3961026","name":null},{"address":"346001263089D83465A72C6DB5EFBC32359111A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vdnWYA28lp43YkD0e2VExAcYPadTFh/Hpes0O0a4p20="},"power":"3960055","name":null},{"address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Fzeq1bTZn9T8Wev9O8/Huzs1nw/OXl0iTepDFRMUko8="},"power":"3960033","name":null},{"address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sAD409SvbABZBr0vCmjL6JK6XVQgQP4RM7v/Oiz/f88="},"power":"3957948","name":null},{"address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","pub_key":{"type":"tendermint/PubKeyEd25519","value":"27PwyrHHY/ndxqNrL6SdHomL4hR3JAJ5QMdQFYRlS9I="},"power":"3881201","name":null},{"address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"a/BQji6ozSlxXzMhtW4RGybuZ81s6tQKSPhO2mGIU4c="},"power":"3000010","name":null},{"address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dO71IfBvwwwJ6cEzc9oT1FqU0CUdckJV5F53kDYb22o="},"power":"2000006","name":null},{"address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D9iPx6VTH+xeewFFWfnI+a7dM6Y5Y9h/5S4WHro5wUQ="},"power":"1003008","name":null},{"address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"BRvI8B8k+QrDeOgdBNb7mLCbNEMatJNqDyZttdGtQm0="},"power":"1001309","name":null},{"address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"VXn41Fko8YeJ3vVvYy/yUtqfVbCv7FTivuDclSrw5Pc="},"power":"1000893","name":null},{"address":"E309A8AFFF70D04126D04BB53071B6020580D104","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J0kLUI0gmvWfWvzoxHaqwzXF3+VARlAIMGCRfB6Yj8A="},"power":"1000210","name":null},{"address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gN5Cln7uU3AVQYzT3QGgggv/3aN+eIewd6m5OfPpkTs="},"power":"1000042","name":null},{"address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","pub_key":{"type":"tendermint/PubKeyEd25519","value":"F3RJktKCIoDGEBWXgpDl2+LgNbq5X0rS8eXnY+i3aIY="},"power":"1000038","name":null},{"address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oRz4ydtLca6+HfffYIRv0PCsTm4xKBdYpx85lisMWng="},"power":"1000037","name":null},{"address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oYhHHoROhbAIzOuST8Qyua7O611uIr3NT2yyibK5x7Y="},"power":"1000020","name":null},{"address":"88731522401F260D5C253222CF6EF71586A192D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"m9gm7H1kmxvPzyo5ubgkmqKGQbJFHst9My51FLe2HeM="},"power":"1000009","name":null},{"address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cPgsoC0NIVUAe42qmzfbrLaznvYZCh1z92Q35D0KZOc="},"power":"990479","name":null},{"address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"PRXS/zL6clsHN2Srl49mRV+W+eL/g7DgY1MG8eu/8K8="},"power":"990174","name":null},{"address":"5769499735A69F335467D419764A69FAFFE29607","pub_key":{"type":"tendermint/PubKeyEd25519","value":"HnEoblS3w9JRSFqXX/2RCippz7tQD/ShYts+tGHoSBM="},"power":"980425","name":null},{"address":"113388853F11E28044A4ED3B11DF745D00D709CD","pub_key":{"type":"tendermint/PubKeyEd25519","value":"61X0w6XUKooaWi4FYzZghd6kJDIFFifK+EpMJWTHSaI="},"power":"509044","name":null},{"address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ba80uJncfcmlWoFM/AlzMI6Mut7SyDJTpbNV8kwMXl0="},"power":"502561","name":null},{"address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Y0SMVwQK9FHbFi7ykZSwah3TG56saeI0uTMXYvyb9dY="},"power":"501737","name":null},{"address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"EiSlqpx/n3VMPFtuTAa++axavjZ9yZzlTa3HtCz+lsI="},"power":"501375","name":null},{"address":"924090B949A3A3A43AEE52C4DAE342332C57B684","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cseuElK5A+VoeuKMvrm3AOTuzII46kf083lVMGpRLDo="},"power":"501271","name":null},{"address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QfqtiQS1sJXJKLIPYSoHTL1NtSfwm933fD1wOqgBxJI="},"power":"501058","name":null},{"address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5bxQwVfFqo0YqTMKMIn0Kmm5SR8QsYGps/x9CUtbFI="},"power":"501050","name":null},{"address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1EE0IXUX+xqvd08toyjMekOX1kNMzEmY2FLNe00sUg="},"power":"500841","name":null},{"address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Wblv9P9x2vItElCo/uoJGPVcB+bMOExuq+fE8+rVfrk="},"power":"500423","name":null},{"address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","pub_key":{"type":"tendermint/PubKeyEd25519","value":"N8ncRVbJpyffC98xo+mxWdqm/GamCJkVTB0YeM8gwkg="},"power":"500401","name":null},{"address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","pub_key":{"type":"tendermint/PubKeyEd25519","value":"GzwPkML4PmjOdcTvr2pm6rjO7cBHrckZR3oe2w4E+FA="},"power":"500018","name":null},{"address":"D5CABF35D9C01401B32540F938BE59FA2B044067","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Bcsbz2eNu1HWCUW9IkzHCZ6ACMxf/sepz12Q8YCdUDM="},"power":"500014","name":null},{"address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","pub_key":{"type":"tendermint/PubKeyEd25519","value":"tF609cLwhEnpi3W93lYIxE1sG/VLbvFKRX0wOzAQxeg="},"power":"500009","name":null},{"address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gmdjSSfvgwXEAJ7CEMDH0Tv+cQSEFujwSIFdR87tWZA="},"power":"500006","name":null},{"address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MJlbI1M3aILcOMSigyPMolCpjfQPzEsagrtZTN+9z6E="},"power":"500005","name":null},{"address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DE8/atJOsW6TA3iDRklz5DdI8j3Tx95o0nOhwkbkvBQ="},"power":"500001","name":null},{"address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zv4/6wZv5pwxuovxaC72oHNW0TAfiH/N+vsilZfiyHc="},"power":"500001","name":null},{"address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vYKrsdaWTO7YnMgWoUGWKO+A3XwgvXYoB+HNVjBkWAA="},"power":"500001","name":null},{"address":"E5183117268691950E77D53340C23857662CC908","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4k08zQEeKnu5auA0Zp3h5xfNfS6K5LfcN0vnAhNiyz8="},"power":"500001","name":null},{"address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"8yHvjPOugBmpP/D0FOfdpQ6oyiymtS1J+U3lNC/d/2U="},"power":"500001","name":null},{"address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"w5YcK+X1Uv6NVRKzY+4qaSw+Zum8CNDVC0+ip0NpQ5s="},"power":"496178","name":null},{"address":"633744F3BE877E6DF590E72E99425BA653156B93","pub_key":{"type":"tendermint/PubKeyEd25519","value":"rD+6Hqi0NsOsZgsjRAP2BbNtxWcieiDmmh3tng63xDQ="},"power":"495995","name":null},{"address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XuXuQxuSJIdpW49/wAalXxyjvuV1aGlamnpg+PDyu/A="},"power":"476704","name":null},{"address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ps7NCfnD+Nkvkgp8mtnh1S57i5OvVKymdrW1RDktbHk="},"power":"201075","name":null},{"address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wXe92Kj6b2uv5WP2yMffYDJ7naD3T08jneI8tQuohIM="},"power":"107519","name":null},{"address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","pub_key":{"type":"tendermint/PubKeyEd25519","value":"qgVzfy4FKDxIrJ/S0a31SHRL1OJZzsxkGMVEW8flsAs="},"power":"105245","name":null},{"address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Dq8TpiZCrf3fzg/sbMm6Ae5Ty3V1WPEtf1lKqFXVBU8="},"power":"102441","name":null},{"address":"4A3918A6D02D25290B243A86618071374FADD87B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"nuKCeeyYPNP/AwbavdBDum3sB8I7D4TCC4sFbPp7MPQ="},"power":"100448","name":null},{"address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XB08MBTE4Rsf3/11MNd+vtdzv0xTvKzGc+7/28Z4En4="},"power":"100370","name":null},{"address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7CT5oKkYGXFByTi8glX/46KCivpVffTBvic6gQL61G0="},"power":"100301","name":null},{"address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oJEFTe9oP7psA7onwhzs/17uEYyVi0FDqEZs2/9mGzM="},"power":"100226","name":null},{"address":"2131A959A819C085AFA86E560D5EC0DF1D632827","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Tac4dLmlfr+reh8jMPLQTGXYUBvY1cp1NtN2y1zDuDA="},"power":"100215","name":null},{"address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","pub_key":{"type":"tendermint/PubKeyEd25519","value":"g/lPk5YCZBxUxlLNgf5qzQN//wwNhIE9HH9w3QX1pMA="},"power":"100162","name":null},{"address":"F7A4EEF357935737058F08804DE4DD03144E960D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"yfV2cDweDavOEDVNWtOYuHcwONDP4jyC/ZG8TUruRD4="},"power":"100136","name":null},{"address":"0A957E96258B8BC5669C9A4DA146532C93E99242","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dJdeXyHrKwqKAboLkSfsmvdQ+WRfYQTz+DbJQDeIFIs="},"power":"100130","name":null},{"address":"B07503589534AAAAD60836B33245410AD11CCEB9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"NVy8f5VLbLWBLrnWMeP+sIkt0iVW4Q3ESepiMx0+j4E="},"power":"100125","name":null},{"address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DP6+z/+64vbsAOx3O8Ej+C9iA572eU5nxlUfGoMB89M="},"power":"100121","name":null},{"address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ZhjOncfNrailm0sDSE0Om3wqYKL5w+QwBowGnkwzBrA="},"power":"100105","name":null},{"address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwSHuhiiooJGDeqHgh/cFoUudQv0zloyeiz400kyv8s="},"power":"100100","name":null},{"address":"F6D5482C2405A9844A1EB215148387AD18800D32","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MwxKwbDR+Pfj2kb8e/mnRy7gLw4n2oJA4qe/E8K6A5E="},"power":"100085","name":null},{"address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3IevyShLKCWeb5joXQjcpPDsvQWnk7bbHLqCd1td7sE="},"power":"100050","name":null},{"address":"50922F9E58F64B3A219887F67117E4CF714AF490","pub_key":{"type":"tendermint/PubKeyEd25519","value":"95WzrdnBvJzBBrOPjORQM0u/70LJnpyvZha6XAvS+T8="},"power":"100048","name":null},{"address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7d0Y9SKn6bfYtn1J9buGsXImkkPHl/bQX8gI7J6Grjk="},"power":"100045","name":null},{"address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"kWIFV6puc+0TvyMPwreUkcAJFHANXbWoLGcTJEDLQPQ="},"power":"100014","name":null},{"address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","pub_key":{"type":"tendermint/PubKeyEd25519","value":"9FusyXhw+gECqAjvHefpCpSS+KQ/fDltXWFy+5HfPcE="},"power":"100011","name":null},{"address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwJhFD9crCT0jEcZi7TXYGo5/tLfRrFGb9C5EYDlHRo="},"power":"100011","name":null},{"address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"WCwJZKhAwYmOH4Eo5TXvsS9W8KqEx1Oi8mj/gfyuQic="},"power":"100011","name":null},{"address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sJQZYhdp6x/l6MQ40Pj2880J6Q/t3433EZglkk1yYaA="},"power":"100010","name":null}],"proposer":null,"total_voting_power":"511862423"},"next_validator_set":{"validators":[{"address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"l/qNaf4JDxnhP+6Pf+2OSAJYksSIkjyefYCDvZPoahA="},"power":"74052443","name":null},{"address":"762CBA617226A799D898F134DD12661C7F1129EB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE="},"power":"70555622","name":null},{"address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","pub_key":{"type":"tendermint/PubKeyEd25519","value":"njq3L6yQabWMjmh9QjBobp2XOdNytaLPoxFgY2Qd3i8="},"power":"64650439","name":null},{"address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","pub_key":{"type":"tendermint/PubKeyEd25519","value":"259mAZKhNLksTkJ7qJZf+ZreaPMQtBY7NDeslqPRa9o="},"power":"28001060","name":null},{"address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J8wAKpZrD9kRbewJDMLQAuYkYNh33PhCg+wcdVcGxIw="},"power":"27553991","name":null},{"address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D3wP4IWMZcMt9UHVzFP2J19FDCP/732nvtT/f3CIatQ="},"power":"25298561","name":null},{"address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"2XKroLDmwSjW8Z0ZadGF/Co/6Bo5OreNldOxj9fl/Ww="},"power":"25000168","name":null},{"address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3rvnDucNb0+ZSdhfQSzjdFSFiZWUGerlEt4hp1EyHKM="},"power":"25000019","name":null},{"address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","pub_key":{"type":"tendermint/PubKeyEd25519","value":"UEKnFx4sn4K1aIPxrCu4zE3+Vr4vMGgIeu2iFAQsUH8="},"power":"24714090","name":null},{"address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"i/Zow0IiKpVFWRNxOwN+Fqe9zVj9VY+Pn8+YsuSo9/E="},"power":"4066863","name":null},{"address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"B6H09N1cxmSXGgqTuAIphe7ESJsCj687/8CYiKBTh4w="},"power":"4050758","name":null},{"address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4TpozS4FflJmfBg3MYhLw12UeVUSELod0fdnX4tAQgs="},"power":"4048910","name":null},{"address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LSpewjhpxXBs00/L2L6DQJabXcSoTzmjqZNTIw5DSCg="},"power":"4048857","name":null},{"address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"SfFXATPCbIeRUsb9RP+BfdYOH0v7H2aGbPGx1HlR1I0="},"power":"4030218","name":null},{"address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5QOLCS5zoZZGk7ZXnaU883fSQAhwneIvP98XcjOte8="},"power":"4023467","name":null},{"address":"9079C978817165244C051EFCE5AD163AAA905C6F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"fODnMY6gDPpnDlAsSQ2b6M5u3gjYNaKq1JL6LBFShzM="},"power":"4009700","name":null},{"address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jqBYsfBjFJhudulObGgaMawaeccpj+21nfs+Px6oNIY="},"power":"4002311","name":null},{"address":"11637B088406D4F3EFF52F2230C8068D230C7611","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gcI3uuOTA3ZAVCMsLawhjUt7cZc/EBJeipq9XGavEsg="},"power":"4002024","name":null},{"address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wdZ6voJ0Kdh/iJvnzjS9oAiSRtr7A2S4mifU3xFfEXk="},"power":"4001100","name":null},{"address":"BB408FA902A7B6A938C788957B2A874153261EC5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7rE47Ol0HqaZhnQQqlx5BD8rNGv6yTcRQANXtMY7y4g="},"power":"4001076","name":null},{"address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zj5o33wP8tFPM8qgoC4upsLQvrAc/DGT2J4JG+LhOJ4="},"power":"4001057","name":null},{"address":"F005689992F73B55B537461AC0AE0DF9694B36CF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"KgescyXaO/6YrE/GIuqmFdP0xXTqHUflMAH40HDm/20="},"power":"4000714","name":null},{"address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LKwKvQPVTwxwW4UDpyIvGW8Sa9sUdaxhhhVdOigrEyA="},"power":"4000566","name":null},{"address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ony9i2cN/h1wawOv0WN6Ql/9lDjDeLgOVCl1fRtuyDI="},"power":"4000504","name":null},{"address":"98271A1B3690F4EC867C760DBCA3754684F485AC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"k3zGTt9YVhopwi6iL+f/XYSj7cZRT+fcPlpwsojLsvg="},"power":"4000472","name":null},{"address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"feFjsaWtjmxYp6N+1r/9Lnd4o29skxSJclmebnk49Ao="},"power":"4000469","name":null},{"address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1QMroz50WA8c/IREfyr7Mm8S75gRCfuk0Ea4fokb4E="},"power":"4000103","name":null},{"address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ps6HB6/GSvuY4fKaszGLXMdHVk38ASzBcGBXeVVeDMo="},"power":"4000028","name":null},{"address":"28B6061D5E269B3585F019E1748E32CA9F34E739","pub_key":{"type":"tendermint/PubKeyEd25519","value":"CIc6ZcjHkdfYEzQqwXZBlYVTl13ZxAinYLLgHszHVgY="},"power":"4000012","name":null},{"address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"OKWb9Bw4pE6tfYtZiigi7A8ecGnCVBiJt2h1P7o1a7U="},"power":"4000008","name":null},{"address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jjLleXjmBwA66V5gejueapJUSYqb5W+oYSGXy/QLEQk="},"power":"4000007","name":null},{"address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RYrMwDTpJWv67sFVwKtmS+UxlN7hljKGWJqOsutcB1s="},"power":"3991125","name":null},{"address":"0DC59C626E4753D889DE2D3262A9A613E754668A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"1UlN1J5cR4XlFifpA8IA7A+xa3NQ1sJ/1IhssJQ+xEM="},"power":"3961059","name":null},{"address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ueUh8xh/b1zlBcCgblxHrZ9impMwKOkgyG5P3f1HkjE="},"power":"3961026","name":null},{"address":"346001263089D83465A72C6DB5EFBC32359111A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vdnWYA28lp43YkD0e2VExAcYPadTFh/Hpes0O0a4p20="},"power":"3960055","name":null},{"address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Fzeq1bTZn9T8Wev9O8/Huzs1nw/OXl0iTepDFRMUko8="},"power":"3960033","name":null},{"address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sAD409SvbABZBr0vCmjL6JK6XVQgQP4RM7v/Oiz/f88="},"power":"3957948","name":null},{"address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","pub_key":{"type":"tendermint/PubKeyEd25519","value":"27PwyrHHY/ndxqNrL6SdHomL4hR3JAJ5QMdQFYRlS9I="},"power":"3881201","name":null},{"address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"a/BQji6ozSlxXzMhtW4RGybuZ81s6tQKSPhO2mGIU4c="},"power":"3000010","name":null},{"address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dO71IfBvwwwJ6cEzc9oT1FqU0CUdckJV5F53kDYb22o="},"power":"2000006","name":null},{"address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D9iPx6VTH+xeewFFWfnI+a7dM6Y5Y9h/5S4WHro5wUQ="},"power":"1003008","name":null},{"address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"BRvI8B8k+QrDeOgdBNb7mLCbNEMatJNqDyZttdGtQm0="},"power":"1001309","name":null},{"address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"VXn41Fko8YeJ3vVvYy/yUtqfVbCv7FTivuDclSrw5Pc="},"power":"1000893","name":null},{"address":"E309A8AFFF70D04126D04BB53071B6020580D104","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J0kLUI0gmvWfWvzoxHaqwzXF3+VARlAIMGCRfB6Yj8A="},"power":"1000210","name":null},{"address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gN5Cln7uU3AVQYzT3QGgggv/3aN+eIewd6m5OfPpkTs="},"power":"1000042","name":null},{"address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","pub_key":{"type":"tendermint/PubKeyEd25519","value":"F3RJktKCIoDGEBWXgpDl2+LgNbq5X0rS8eXnY+i3aIY="},"power":"1000038","name":null},{"address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oRz4ydtLca6+HfffYIRv0PCsTm4xKBdYpx85lisMWng="},"power":"1000037","name":null},{"address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oYhHHoROhbAIzOuST8Qyua7O611uIr3NT2yyibK5x7Y="},"power":"1000020","name":null},{"address":"88731522401F260D5C253222CF6EF71586A192D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"m9gm7H1kmxvPzyo5ubgkmqKGQbJFHst9My51FLe2HeM="},"power":"1000009","name":null},{"address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cPgsoC0NIVUAe42qmzfbrLaznvYZCh1z92Q35D0KZOc="},"power":"990479","name":null},{"address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"PRXS/zL6clsHN2Srl49mRV+W+eL/g7DgY1MG8eu/8K8="},"power":"990174","name":null},{"address":"5769499735A69F335467D419764A69FAFFE29607","pub_key":{"type":"tendermint/PubKeyEd25519","value":"HnEoblS3w9JRSFqXX/2RCippz7tQD/ShYts+tGHoSBM="},"power":"980425","name":null},{"address":"113388853F11E28044A4ED3B11DF745D00D709CD","pub_key":{"type":"tendermint/PubKeyEd25519","value":"61X0w6XUKooaWi4FYzZghd6kJDIFFifK+EpMJWTHSaI="},"power":"509044","name":null},{"address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ba80uJncfcmlWoFM/AlzMI6Mut7SyDJTpbNV8kwMXl0="},"power":"502561","name":null},{"address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Y0SMVwQK9FHbFi7ykZSwah3TG56saeI0uTMXYvyb9dY="},"power":"501737","name":null},{"address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"EiSlqpx/n3VMPFtuTAa++axavjZ9yZzlTa3HtCz+lsI="},"power":"501375","name":null},{"address":"924090B949A3A3A43AEE52C4DAE342332C57B684","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cseuElK5A+VoeuKMvrm3AOTuzII46kf083lVMGpRLDo="},"power":"501271","name":null},{"address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QfqtiQS1sJXJKLIPYSoHTL1NtSfwm933fD1wOqgBxJI="},"power":"501058","name":null},{"address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5bxQwVfFqo0YqTMKMIn0Kmm5SR8QsYGps/x9CUtbFI="},"power":"501050","name":null},{"address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1EE0IXUX+xqvd08toyjMekOX1kNMzEmY2FLNe00sUg="},"power":"500841","name":null},{"address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Wblv9P9x2vItElCo/uoJGPVcB+bMOExuq+fE8+rVfrk="},"power":"500423","name":null},{"address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","pub_key":{"type":"tendermint/PubKeyEd25519","value":"N8ncRVbJpyffC98xo+mxWdqm/GamCJkVTB0YeM8gwkg="},"power":"500401","name":null},{"address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","pub_key":{"type":"tendermint/PubKeyEd25519","value":"GzwPkML4PmjOdcTvr2pm6rjO7cBHrckZR3oe2w4E+FA="},"power":"500018","name":null},{"address":"D5CABF35D9C01401B32540F938BE59FA2B044067","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Bcsbz2eNu1HWCUW9IkzHCZ6ACMxf/sepz12Q8YCdUDM="},"power":"500014","name":null},{"address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","pub_key":{"type":"tendermint/PubKeyEd25519","value":"tF609cLwhEnpi3W93lYIxE1sG/VLbvFKRX0wOzAQxeg="},"power":"500009","name":null},{"address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gmdjSSfvgwXEAJ7CEMDH0Tv+cQSEFujwSIFdR87tWZA="},"power":"500006","name":null},{"address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MJlbI1M3aILcOMSigyPMolCpjfQPzEsagrtZTN+9z6E="},"power":"500005","name":null},{"address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DE8/atJOsW6TA3iDRklz5DdI8j3Tx95o0nOhwkbkvBQ="},"power":"500001","name":null},{"address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zv4/6wZv5pwxuovxaC72oHNW0TAfiH/N+vsilZfiyHc="},"power":"500001","name":null},{"address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vYKrsdaWTO7YnMgWoUGWKO+A3XwgvXYoB+HNVjBkWAA="},"power":"500001","name":null},{"address":"E5183117268691950E77D53340C23857662CC908","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4k08zQEeKnu5auA0Zp3h5xfNfS6K5LfcN0vnAhNiyz8="},"power":"500001","name":null},{"address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"8yHvjPOugBmpP/D0FOfdpQ6oyiymtS1J+U3lNC/d/2U="},"power":"500001","name":null},{"address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"w5YcK+X1Uv6NVRKzY+4qaSw+Zum8CNDVC0+ip0NpQ5s="},"power":"496178","name":null},{"address":"633744F3BE877E6DF590E72E99425BA653156B93","pub_key":{"type":"tendermint/PubKeyEd25519","value":"rD+6Hqi0NsOsZgsjRAP2BbNtxWcieiDmmh3tng63xDQ="},"power":"495995","name":null},{"address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XuXuQxuSJIdpW49/wAalXxyjvuV1aGlamnpg+PDyu/A="},"power":"476704","name":null},{"address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ps7NCfnD+Nkvkgp8mtnh1S57i5OvVKymdrW1RDktbHk="},"power":"201075","name":null},{"address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wXe92Kj6b2uv5WP2yMffYDJ7naD3T08jneI8tQuohIM="},"power":"107519","name":null},{"address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","pub_key":{"type":"tendermint/PubKeyEd25519","value":"qgVzfy4FKDxIrJ/S0a31SHRL1OJZzsxkGMVEW8flsAs="},"power":"105245","name":null},{"address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Dq8TpiZCrf3fzg/sbMm6Ae5Ty3V1WPEtf1lKqFXVBU8="},"power":"102441","name":null},{"address":"4A3918A6D02D25290B243A86618071374FADD87B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"nuKCeeyYPNP/AwbavdBDum3sB8I7D4TCC4sFbPp7MPQ="},"power":"100448","name":null},{"address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XB08MBTE4Rsf3/11MNd+vtdzv0xTvKzGc+7/28Z4En4="},"power":"100370","name":null},{"address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7CT5oKkYGXFByTi8glX/46KCivpVffTBvic6gQL61G0="},"power":"100301","name":null},{"address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oJEFTe9oP7psA7onwhzs/17uEYyVi0FDqEZs2/9mGzM="},"power":"100226","name":null},{"address":"2131A959A819C085AFA86E560D5EC0DF1D632827","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Tac4dLmlfr+reh8jMPLQTGXYUBvY1cp1NtN2y1zDuDA="},"power":"100215","name":null},{"address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","pub_key":{"type":"tendermint/PubKeyEd25519","value":"g/lPk5YCZBxUxlLNgf5qzQN//wwNhIE9HH9w3QX1pMA="},"power":"100162","name":null},{"address":"F7A4EEF357935737058F08804DE4DD03144E960D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"yfV2cDweDavOEDVNWtOYuHcwONDP4jyC/ZG8TUruRD4="},"power":"100136","name":null},{"address":"0A957E96258B8BC5669C9A4DA146532C93E99242","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dJdeXyHrKwqKAboLkSfsmvdQ+WRfYQTz+DbJQDeIFIs="},"power":"100130","name":null},{"address":"B07503589534AAAAD60836B33245410AD11CCEB9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"NVy8f5VLbLWBLrnWMeP+sIkt0iVW4Q3ESepiMx0+j4E="},"power":"100125","name":null},{"address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DP6+z/+64vbsAOx3O8Ej+C9iA572eU5nxlUfGoMB89M="},"power":"100121","name":null},{"address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ZhjOncfNrailm0sDSE0Om3wqYKL5w+QwBowGnkwzBrA="},"power":"100105","name":null},{"address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwSHuhiiooJGDeqHgh/cFoUudQv0zloyeiz400kyv8s="},"power":"100100","name":null},{"address":"F6D5482C2405A9844A1EB215148387AD18800D32","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MwxKwbDR+Pfj2kb8e/mnRy7gLw4n2oJA4qe/E8K6A5E="},"power":"100085","name":null},{"address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3IevyShLKCWeb5joXQjcpPDsvQWnk7bbHLqCd1td7sE="},"power":"100050","name":null},{"address":"50922F9E58F64B3A219887F67117E4CF714AF490","pub_key":{"type":"tendermint/PubKeyEd25519","value":"95WzrdnBvJzBBrOPjORQM0u/70LJnpyvZha6XAvS+T8="},"power":"100048","name":null},{"address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7d0Y9SKn6bfYtn1J9buGsXImkkPHl/bQX8gI7J6Grjk="},"power":"100045","name":null},{"address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"kWIFV6puc+0TvyMPwreUkcAJFHANXbWoLGcTJEDLQPQ="},"power":"100014","name":null},{"address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","pub_key":{"type":"tendermint/PubKeyEd25519","value":"9FusyXhw+gECqAjvHefpCpSS+KQ/fDltXWFy+5HfPcE="},"power":"100011","name":null},{"address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwJhFD9crCT0jEcZi7TXYGo5/tLfRrFGb9C5EYDlHRo="},"power":"100011","name":null},{"address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"WCwJZKhAwYmOH4Eo5TXvsS9W8KqEx1Oi8mj/gfyuQic="},"power":"100011","name":null},{"address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sJQZYhdp6x/l6MQ40Pj2880J6Q/t3433EZglkk1yYaA="},"power":"100010","name":null}],"proposer":null,"total_voting_power":"511862423"},"provider":"726bc8d260387cf56ecfad3a6bf6fecd903e18a2"} \ No newline at end of file diff --git a/examples/tendermint/script/files/block_2279130.json b/examples/tendermint/script/files/block_2279130.json new file mode 100644 index 0000000000..6d1dca1563 --- /dev/null +++ b/examples/tendermint/script/files/block_2279130.json @@ -0,0 +1 @@ +{"signed_header":{"header":{"version":{"block":"11","app":"1"},"chain_id":"mocha-4","height":"2279130","time":"2024-07-16T21:27:30.456198169Z","last_block_id":{"hash":"6CC4DB10A5D83E5635518FB0406BCDE908F7CF24A8D8FF25564A8E88E197A827","parts":{"total":11,"hash":"18A28290599679F2DEAA656F63419F1F0149E1CD9E8E351B8BC7DAB1F11E1346"}},"last_commit_hash":"2743E7BA347689BA49023C41E74C38FDDDC392F6D9EDAE701CB69825261D0013","data_hash":"8709D5ABEAA65D170726E12B038A583062443192C83C72259FF1688C5350866B","validators_hash":"761B52540AA384D2B2CEB9D31F1619DB75498E9EE162949E30EFE10D14BC405A","next_validators_hash":"761B52540AA384D2B2CEB9D31F1619DB75498E9EE162949E30EFE10D14BC405A","consensus_hash":"C0B6A634B72AE9687EA53B6D277A73ABA1386BA3CFC6D0F26963602F7F6FFCD6","app_hash":"73EE45EA6D30D5DF58D0EFA2CFAF04026EE7788FF2BD83E2387A4D642007D3F1","last_results_hash":"39D9A53FBF478B90F2ECD3B72EB0B7179B433823FD85ECC34D1FDA5F397F5AA6","evidence_hash":"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855","proposer_address":"4A3918A6D02D25290B243A86618071374FADD87B"},"commit":{"height":"2279130","round":0,"block_id":{"hash":"43BC5267791ADBA07AF7FFF36F91173B65E07F342E2D8EB69BEA7C11CA6D9470","parts":{"total":12,"hash":"D00584AABC61C2C37E86E8624DB8C3BDEB00349BCF69CB6881349776C39A65D5"}},"signatures":[{"block_id_flag":2,"validator_address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","timestamp":"2024-07-16T21:27:42.817717878Z","signature":"RuJSXCpXQbRfv3LnO7y7aNWFIKSa7kWN1rW+Mox7za9OZfmxPLCsEyacDh4h0gmPklP1xILIdpBPSqfZfZxkAQ=="},{"block_id_flag":2,"validator_address":"762CBA617226A799D898F134DD12661C7F1129EB","timestamp":"2024-07-16T21:27:42.615806652Z","signature":"hDZCIxLc+Z7jI0rMhOEoOxCXZb4N4xwtHFc8AsyA58ZT7gq3SdLCGtF/l6BlMNrFt05XbN1nbYLCI0DOtlJfDg=="},{"block_id_flag":2,"validator_address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","timestamp":"2024-07-16T21:27:42.650594215Z","signature":"rEkVGnXg2wqqnCJedlxmJ9g7Bk/H4cX8A+bpKnTkqIhF8I/DuRIlAeMVkYL82KoQME3YzTHVt37l0WfnIHEtCA=="},{"block_id_flag":2,"validator_address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","timestamp":"2024-07-16T21:27:42.638326721Z","signature":"8EeiWtzYiJ/UsJ+bEIrTlVKMXiTpNTJIo/947LdJC3VFOvH/VoI33upf5ogUD/Ffwkx8TNlQNTUJbxPlcjPtDQ=="},{"block_id_flag":2,"validator_address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","timestamp":"2024-07-16T21:27:42.14850095Z","signature":"ux17F/FGhjyEXaoGprvRKaxiJ5F9sLzdjdHLuqwKzpDiONu2q5Lc/tworX5TG6LXmV6+vkLFGEWa07LlAWwECQ=="},{"block_id_flag":2,"validator_address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","timestamp":"2024-07-16T21:27:42.68464798Z","signature":"NJh51JhEtOcqNBW8uzCOAU6Qn2/jtrw5Z7xjzAIK6u/Jd8DQO0aomxUj9fgvgZQ9ocy/QrKXxi3gxnpGNr3iAw=="},{"block_id_flag":2,"validator_address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","timestamp":"2024-07-16T21:27:42.561172825Z","signature":"MLoyaTTbXNAk55OxlmPj5RceNVmPHpmVNjt5b2CrMLF682niaaSDwN+xChZUTsl999Vt/SHy4ZMjaKHIcRIgDA=="},{"block_id_flag":2,"validator_address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","timestamp":"2024-07-16T21:27:42.679828009Z","signature":"/FhVaTEyuvSDw1D3NR9e97YzUt1DK3g8XGBKZA1OJjvRV9+l8+NjYXXeCm8PSiu7Kl++tDMj5r9N81SaSstlBg=="},{"block_id_flag":2,"validator_address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","timestamp":"2024-07-16T21:27:42.637123387Z","signature":"SK4F3v96HJa20oLJq7M9tx7tOav8HI9qOvzoZQUaevZgk7SjYfXRMm62KljAuACmKtUMBk0qoiCDrkDcvhi7Dw=="},{"block_id_flag":2,"validator_address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","timestamp":"2024-07-16T21:27:42.662381061Z","signature":"lZqtwUH+qqPJ4DZ9dNUDJYXbq5hckrRnCyygSPmp7JVK8V2DOQ3XxEkNdXrKXqsQLZjFkD1bWWaToZ1kBnpWCA=="},{"block_id_flag":2,"validator_address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","timestamp":"2024-07-16T21:27:42.677602664Z","signature":"EfiQNIuAdBs/S3YjAAqeyahHuNmdYu+QSR0h0GloX9N6SjjXKHylOId+f7axO5PQZ1slRkloPkl5NH3dXb3uCw=="},{"block_id_flag":2,"validator_address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","timestamp":"2024-07-16T21:27:42.694508191Z","signature":"zaqYg5nbQmhES6zgFgjDyfel5frzZwogkcCNAnXsvbqPL5ASEIKus/jdSJIE4vpz+1ED+V7MBLBkkvdoAoQ4AA=="},{"block_id_flag":2,"validator_address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","timestamp":"2024-07-16T21:27:42.813717174Z","signature":"lRRzcN3tsomu1DwL6HVHPDOC4/FNks2xO/EI9zQrt3q1UObVeSMBuU9R4SiznHgqAtZQt7/EsF1Ql0wY2jjmDg=="},{"block_id_flag":2,"validator_address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","timestamp":"2024-07-16T21:27:42.842816403Z","signature":"7+KuOFHmW0HNhXg/UYBe/+UGo0pRpRa9QqvC4nWoY0ACo3PO2CcPVblX/60nTSC/LPo3Qxhbepy1wVe0Pua2CA=="},{"block_id_flag":2,"validator_address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","timestamp":"2024-07-16T21:27:42.737936119Z","signature":"JLjF+r/ES3e2xdpUnI3lAZ+cJ2jdwhxYXZq8a1CBRfqhfCrHGZGGM5TpjGMXAsGzl/FpCSG1INF4v+f3klCXDg=="},{"block_id_flag":2,"validator_address":"9079C978817165244C051EFCE5AD163AAA905C6F","timestamp":"2024-07-16T21:27:42.71952497Z","signature":"VIKo2y/y786DDl4S08ANsv7SN2iOGuGXXHhVay+p6Htmxj+9Zy1w6xLAnO5CuGyXI4iT7MTs5AAW+xkHiY11Bw=="},{"block_id_flag":2,"validator_address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","timestamp":"2024-07-16T21:27:42.802561542Z","signature":"SqY1Zx/qbtexqppYhvlFR49bFWfqrF9Pp0DUPtkJ1ppmXGpxqMFTDlGkvqSMVpg+85Ny2oNqTLOLozQMtDLXAQ=="},{"block_id_flag":2,"validator_address":"11637B088406D4F3EFF52F2230C8068D230C7611","timestamp":"2024-07-16T21:27:42.634522027Z","signature":"r/Di5BYzEeRouJQsogaaNQLsvgvplmQUe+WGCyGQJUi5cJBAINgSSHZftv1iBqt3JP39e4xYAXxzCaolg/mXBg=="},{"block_id_flag":2,"validator_address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","timestamp":"2024-07-16T21:27:42.661924157Z","signature":"gMmlHiJh873Mzqt2RiKVJwPz8jmvlDuGZEkj1V8tT2mjnNwQhfS/qHpOsqO/oO2B12oF9XkOK54wKohmfyNRAw=="},{"block_id_flag":2,"validator_address":"BB408FA902A7B6A938C788957B2A874153261EC5","timestamp":"2024-07-16T21:27:42.758642629Z","signature":"97+chYE68FLap/IgJ8DAIP2544sSE73hBd+ptrRsgyMAu3KR9It1YlQri1S6MEp/KDpud98AssMJuf76E1X3BQ=="},{"block_id_flag":2,"validator_address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","timestamp":"2024-07-16T21:27:42.630780569Z","signature":"dzk2o22xe6jYvvWsTpr5aqgjw+hITzuPrhSxEMa3qWEfqoy2itVBO0Q9Eq5K43fE1/pxO9o9lO5AE2OmoaNBBQ=="},{"block_id_flag":2,"validator_address":"F005689992F73B55B537461AC0AE0DF9694B36CF","timestamp":"2024-07-16T21:27:42.746670619Z","signature":"iilRB5G7zFoqbAepzLwvGI+O5+pbM4fk76m07JvQ3zluNeOAqwjW4UlouyNYOQmbE8UbJ6tqq0gIiRoyrhRjBw=="},{"block_id_flag":2,"validator_address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","timestamp":"2024-07-16T21:27:42.845158495Z","signature":"TNqwHE3f/0qeb1Lcah6ZerIL5s07oZQWjz/iAPvwgxeJEktfvH7c+0TUJsX+C8QRJBLHAhv1OdWTn1P8XcHqBA=="},{"block_id_flag":2,"validator_address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","timestamp":"2024-07-16T21:27:42.809635737Z","signature":"cJwHa3k0a8YrDiaJWUsg1P8+IhuO6pblcUpTdP6CaJ0ZpF0K4mHWVkwfhEQ7N5GU1mGlqpIWtGUKYP4wBnRVDQ=="},{"block_id_flag":2,"validator_address":"98271A1B3690F4EC867C760DBCA3754684F485AC","timestamp":"2024-07-16T21:27:42.604498661Z","signature":"SjcFdtYEti7s6Nrwkd46MP68lHjk9EpiCMF+GoEHT3I4c6mXDfXA8KupBQ9dk6dMEgBiWhBEQDtj6Lm2kcafDg=="},{"block_id_flag":2,"validator_address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","timestamp":"2024-07-16T21:27:42.71762574Z","signature":"FFXZM3CyxS9cdVQma+w4hL4PpZLzgkyWhDbBcmhpjSM5PyP0moISFzyk4P/ZbhLxHoOGTqMwMZ92yTWoNWkNDA=="},{"block_id_flag":2,"validator_address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","timestamp":"2024-07-16T21:27:42.834482154Z","signature":"q2YTYx5174wOyb8PdfuJoIYcww8/+RKUwLQFhnhdpZkf2Nqa8a40z4vN2tKye1Uc1JjFNhPyWwQ4C2zf/QuLBg=="},{"block_id_flag":2,"validator_address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","timestamp":"2024-07-16T21:27:42.581614043Z","signature":"gleFu52vwH8NWA0zkk+t5dJgQgcpkMSPeXy+ndu9SOaGN5OfNEfrF25KcXiMsJe5ju+yC6UtA+zj+sSAinoiBQ=="},{"block_id_flag":2,"validator_address":"28B6061D5E269B3585F019E1748E32CA9F34E739","timestamp":"2024-07-16T21:27:42.805998384Z","signature":"zmam6GpEPW/Zjyq7vsKHReic4AGfXHCbS9DaxwcRNOPcxKSCWmK8VkpeutqI90n2oVEN2eYucL0E2taWb3wNBg=="},{"block_id_flag":2,"validator_address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","timestamp":"2024-07-16T21:27:42.622604436Z","signature":"HbO7gktREZwnf9XHIgQexHHlng6w24GMtPmxPX+sNxBH+UpA/HoRzsy9BnQP26vtFBE/DIG6YQbBhVzO8tAfBw=="},{"block_id_flag":2,"validator_address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","timestamp":"2024-07-16T21:27:42.817779881Z","signature":"JKem/x3QBFmMfiSvM6nR3gVZyOFnG9TJbbfnRmunuUWWd5c6kTS7aQ8fVZBoTFMxrp8PBsjDE3lwW4RGpfryAQ=="},{"block_id_flag":2,"validator_address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","timestamp":"2024-07-16T21:27:42.739659876Z","signature":"XQqpQ8rV6nlfJj8Pf0cNpCTqU6mxOiTWTL1Q34QgUWhvRkW6AeywwBXumgCcTIztpqaTZ1qs4KLCGwVt4ojEDg=="},{"block_id_flag":2,"validator_address":"0DC59C626E4753D889DE2D3262A9A613E754668A","timestamp":"2024-07-16T21:27:42.701319253Z","signature":"z6LMv/Zq81TE7W6WRP1kfJL/CnQOMGzwtkXI3nL2W+nDdn29dc5y74BBwNDs5VYZ3148aAuJQl/+JvnJp/4FDA=="},{"block_id_flag":2,"validator_address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","timestamp":"2024-07-16T21:27:42.773553762Z","signature":"2plDZ6TBtlsCnz8JH4XhKauvScQ70oqfZo3YaevIL/1UCE9uSz9Zq+Uax/IT905i8QTvYO0mdh2zrAymRARmDQ=="},{"block_id_flag":2,"validator_address":"346001263089D83465A72C6DB5EFBC32359111A3","timestamp":"2024-07-16T21:27:42.627266683Z","signature":"F7ruz20nyGDBKRkAAWRMW0t+LwzzJS4sFFn6DszJjPHgQIsommbL6539eLROAKo+Rm9W9PyYFUSedki8+UzLAw=="},{"block_id_flag":2,"validator_address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","timestamp":"2024-07-16T21:27:42.671734765Z","signature":"yofG9qeJcsq3EbPuZ9cxZhxhUDiAfBdmt5XbnwqU9RRQj7ICnZRgFxKEUId7k0J1Ak5ZfSQmZFgZ4kGF7I8FBw=="},{"block_id_flag":2,"validator_address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","timestamp":"2024-07-16T21:27:42.594059674Z","signature":"whFdl7B67q4UJS+Nt+Ash2zVKxD7qWpzLESEXk3qLwifVqwpwYmb27OwEM3oVSvUNc1/vpGYxAQG3uvXMICKCA=="},{"block_id_flag":2,"validator_address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","timestamp":"2024-07-16T21:27:42.949247768Z","signature":"FEtEIWA7oQnksOWaEIS19a2FQeuKZuvQEmOMydGOEiGMgIf8jHw9adz8sKX2AaFU1Rimx8uURngzww2dwQIcAw=="},{"block_id_flag":2,"validator_address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","timestamp":"2024-07-16T21:27:42.669478745Z","signature":"evsikNo9hEkh9heQD1swkYDDJy9l0ymwRidRMvvQtMN5FUCFUiavPUGMHEx7fM5ZwJMC4XmbLGF0PIroylavAA=="},{"block_id_flag":2,"validator_address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","timestamp":"2024-07-16T21:27:42.748229507Z","signature":"k/Lz7ndpG9HuLGheNvg8eweluR9dSCXg3Ppgcx7/uO9T2qQsh1LwTvJyMVF3dvpN9uB4eMeQor5hb6tJZWJtBA=="},{"block_id_flag":2,"validator_address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","timestamp":"2024-07-16T21:27:42.609439287Z","signature":"ro1IPDIx37i0syqiTnzAhkUCNd3G0NsqnKOn1x7OksA6Sg9+REOQbrrY8Y6d9zN/9IELeqCCG50IEiVLjEnkAw=="},{"block_id_flag":2,"validator_address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","timestamp":"2024-07-16T21:27:42.616348324Z","signature":"wbsw2f2j2Hd0EvDhtiC/wqS6Tagh7msxHTojW1VCjMI89+pX15D4bkSoYE0DPPEspTWYhoLdQSu7dI29G7YPAQ=="},{"block_id_flag":2,"validator_address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","timestamp":"2024-07-16T21:27:42.662591316Z","signature":"OPol6GuVBUKmdKqmTu1W+Rg11L8G7trmlcReK4uy+/TCdW2QEFk0WBJjXXKa7Ii9m66EIijp38obghR8wPmtBQ=="},{"block_id_flag":2,"validator_address":"E309A8AFFF70D04126D04BB53071B6020580D104","timestamp":"2024-07-16T21:27:42.74684106Z","signature":"5taMTnJreOQS490ODXB73Du26AVtWRPSpwlwwVo6gNUUDCifkobSYGQPdOGvhhRBw8nzFDPdxnRYTqGzjWR1CQ=="},{"block_id_flag":2,"validator_address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","timestamp":"2024-07-16T21:27:42.891890438Z","signature":"hK85hrUjzXiaaLsYUi9rkymahw/2JtQvB7JLKVbQUpWX/cEFBHJkeK8eJzDgaVUo9b1sfp1UaSmhe/nqD0lQAg=="},{"block_id_flag":2,"validator_address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","timestamp":"2024-07-16T21:27:42.772064321Z","signature":"ToiJ9OWumG7Eog2urV3zWNKbqfEGJypEtZKCxIr6WQ1IxpTxfL/67DtIDb6AnwLwBWbfRQNGBmNT96eU3h95BA=="},{"block_id_flag":2,"validator_address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","timestamp":"2024-07-16T21:27:42.604920899Z","signature":"TJMhskHGfVxnrXJrGDvdZOE+AaBcSxRkGVYCUr8J/QY/Fy3ss+LmTq26Y2vP4rw1YeMjVImtTiHyedd54xr6AQ=="},{"block_id_flag":2,"validator_address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","timestamp":"2024-07-16T21:27:42.607173997Z","signature":"Y7i80ahnI3jtH+2BSn5GfGpZPC1A2RHZztIwwYQVnMbkHm8cV0Qrz/sGzwWIDIwJGYcUGvucTa9tESNRcTDJDw=="},{"block_id_flag":2,"validator_address":"88731522401F260D5C253222CF6EF71586A192D3","timestamp":"2024-07-16T21:27:42.651391676Z","signature":"aTqiso8PlaTLDuSvLSl8qi+HLg7tBiB42MfGbLzxml6IMb26RxkbYBi7cRaDiIOt6Ma4NR7QxyH+GLc8HgkUDw=="},{"block_id_flag":2,"validator_address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","timestamp":"2024-07-16T21:27:42.671710833Z","signature":"9W/yQf1s6aclXiPpgmNHv5JE4WWQghiLgOqcCGfkNzFhv8ShPn3MlmM1GX4fNPPynjsE638R4X++j5nWlmFfAg=="},{"block_id_flag":2,"validator_address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","timestamp":"2024-07-16T21:27:42.875372427Z","signature":"RgntpznN562psFOd4Wir/XI1UVwLYxhYRVVrsJcDP7RW4jwSMViaMrHyYKpUYxA/5aduvFvpZyq1zIqJ24QWDw=="},{"block_id_flag":2,"validator_address":"5769499735A69F335467D419764A69FAFFE29607","timestamp":"2024-07-16T21:27:43.332919397Z","signature":"5Lffb765q/KOTCT6gZxP/n5fIV7XJSv/71wAqKmo+InkQqDSnCP+2zZOqnPB4Su3cx0CzTOBV96rfqvZ8UCeCQ=="},{"block_id_flag":2,"validator_address":"113388853F11E28044A4ED3B11DF745D00D709CD","timestamp":"2024-07-16T21:27:42.737115319Z","signature":"qA1ZONgz0NyE8QGDn+9yaxnDTvxQ7BPAVhA+soMJFl2SViumkq0td5T8zLkWxZT5rTks7hEusOeXozwsBN1qAw=="},{"block_id_flag":2,"validator_address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","timestamp":"2024-07-16T21:27:42.691757904Z","signature":"guOnnW5g/ok9PpzK2nCZV/dkAgnYh1f5HOWsAj5Rti7ozCBXD4TNgsGJznLLM5IbGWdtuJnZm5WNlqK7ifNQDg=="},{"block_id_flag":2,"validator_address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","timestamp":"2024-07-16T21:27:42.734542989Z","signature":"hR/3H8f7KVefcLf9obDuDGqrFZ2BvzX9njfCjARJypErmzfEQNnrpXsQ9mcY9FnCU3ayqszc+wWEGJ6tPZlCAg=="},{"block_id_flag":2,"validator_address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","timestamp":"2024-07-16T21:27:42.607794468Z","signature":"1ZtTjE0U1HVVX/mPIv5ff0EanPZU3MU0NinUUy2T+OGsDANvNmZuU1TQykhV1jhNtgRubgvnh2SrfiG+d58mDQ=="},{"block_id_flag":2,"validator_address":"924090B949A3A3A43AEE52C4DAE342332C57B684","timestamp":"2024-07-16T21:27:42.855378125Z","signature":"pXd0AezBex8E2KWo/1mwA3VaYQN2vo89o5F9nkI4MmJrlBTPzeTw4PnnJ8CF/nlI3o3utt+urKUcjFGVd4CJDA=="},{"block_id_flag":2,"validator_address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","timestamp":"2024-07-16T21:27:42.594052739Z","signature":"7SwSyH7DQTE0x39WPG1yUJ/1F5COg5Virx1LpISZj8V8AUsQTqeHBqTVuAbEHnw2y9Y6lqw72f9LpuIs/YXFDw=="},{"block_id_flag":2,"validator_address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","timestamp":"2024-07-16T21:27:42.687953664Z","signature":"c2+pSZsP4iLR1/YD4JwzrFjdR8OYub7KtPPbg4+QELXFE8/97UZ9o1WeS1RzRkzw22QVCAIXQJwlDPfu+xk3Cg=="},{"block_id_flag":2,"validator_address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","timestamp":"2024-07-16T21:27:42.666378122Z","signature":"L6GUOSw7BgF9uIM6w30BtiEv2j/vMIBtgzzkeoJ+SdGEy6l1Jx6vZIJrq2/qb2UhB7uES5i9EIRkSd0tBTiPCw=="},{"block_id_flag":2,"validator_address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","timestamp":"2024-07-16T21:27:42.721239647Z","signature":"UD8osfhMrZuyAhyNvibpxlKT3PUfZMagbWtNvD48mg9iqVtjqW8wgY4as+lMt7rNHVxg5iM9UFXBjMBYud+oAg=="},{"block_id_flag":2,"validator_address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","timestamp":"2024-07-16T21:27:42.66981356Z","signature":"eujyhI9a735LXrpJDc3nX/C3odhYxH/ZQVWxDn982VU+AtDCaSmRMl7d80GDOuOd2p3SM5VnUV6XQZaO94F1Bw=="},{"block_id_flag":2,"validator_address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","timestamp":"2024-07-16T21:27:42.668263232Z","signature":"kQ5Va5xknuX/Ze9RYie0ceAh6P3zUIAb1C+C0bcCSEBrDS8fvlgvjmpu8lib5KlfLCLf6rOInhfE/QoqDtCiBA=="},{"block_id_flag":2,"validator_address":"D5CABF35D9C01401B32540F938BE59FA2B044067","timestamp":"2024-07-16T21:27:42.697888521Z","signature":"9YACbk66pmlu7pEcZbALzJX4ENeA9migwpwb25zGAb+DTct+zVQ4EZsTQ8zRQKFGCy3tO5APp10ttTB+S49cCg=="},{"block_id_flag":2,"validator_address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","timestamp":"2024-07-16T21:27:42.665532751Z","signature":"tsFgo13tIBiQfq2NTUUf1OFXS3kEdd6Loc3EFm/F+GTjeqPMPFyaLdrb3191SnjPcEb1rH7EQRPtsamiPwgyCw=="},{"block_id_flag":2,"validator_address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","timestamp":"2024-07-16T21:27:42.679365167Z","signature":"FuH7QQ9kC5fDnHVlmdNZIFe24MSo2EvsNvM0rotgY4byoMNGw5S76R8s/w8eyY4G10v7ME8QL+AoTVyWT29CDw=="},{"block_id_flag":2,"validator_address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","timestamp":"2024-07-16T21:27:42.680511146Z","signature":"QOkyatDyzo2H27pga05twnyMJiayEb+Xplkw5h+dJQZj3VDOfewY3R+bxvXSoeuXStlfz2mHbf2gYke+LiLQBw=="},{"block_id_flag":2,"validator_address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","timestamp":"2024-07-16T21:27:42.784005371Z","signature":"vj7WMSuXvirqN2Vv8lB2blrZ+MIS2j6yRtv9I/0zs/pt5/yp+LfAtBOF0ggrG8IqF0x4DGuSkXIvUrbxFrVXBg=="},{"block_id_flag":2,"validator_address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","timestamp":"2024-07-16T21:27:42.733016807Z","signature":"FClvM+Wn1i8HAZqXvhft4wHoSjXgItCUryno6wHXFYCBXkzmsgjgKIW9Vtxdfvb+Pf0CZi5RAIP09wcs5FkOCg=="},{"block_id_flag":2,"validator_address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","timestamp":"2024-07-16T21:27:42.693054768Z","signature":"dZhb5AkmCyXaV40Rqrw51EjS0QQyi0KjjLG5z/5q4jfXFNC1koYoczXUbUdkpZz1rAbebl79I9cla11S6quiAg=="},{"block_id_flag":2,"validator_address":"E5183117268691950E77D53340C23857662CC908","timestamp":"2024-07-16T21:27:42.718581508Z","signature":"VPlvr/uklbxSkGk05+/7a/QwNgr8Fk3hMj3gQAdOL/2YWZLQVfV+k5oRruHF7qcHxkwW82ydaef8Ad/IRfTqAg=="},{"block_id_flag":2,"validator_address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","timestamp":"2024-07-16T21:27:42.780359836Z","signature":"Pdfdased2NXXjrLUUBvd21GNmrGwJh1djvK4Qwq7PIIEtBcFqXvUU45QL3AymOQYlMfrG728h1MnEFTx3qAHAg=="},{"block_id_flag":3,"validator_address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","timestamp":"2024-07-16T21:27:43.00651579Z","signature":"u5iTTItheZiil9S9Wf1uPTDBSiEmJA285R1FiYa/n+b/p+C4FQU2+Tfyas/LcdhIK1DW4F9exgnVVzNqPFyAAQ=="},{"block_id_flag":2,"validator_address":"633744F3BE877E6DF590E72E99425BA653156B93","timestamp":"2024-07-16T21:27:42.69487624Z","signature":"ShpSUl6yzvMYOaMEcqaU1i0ukYmEwbzG+EOpjt/vkxp0POz1gWjvAdPctyw1zJRWD3LQDTGkWEV+p06Vr13cDA=="},{"block_id_flag":2,"validator_address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","timestamp":"2024-07-16T21:27:42.605252993Z","signature":"qw4jrVJuhBoRPyQPl9v7ipcoLZEI6i6yBdasXnppnnhdi1tHnh8vsORPAZozDwwvEitFGYd0jlUKEBD1p7IhAg=="},{"block_id_flag":2,"validator_address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","timestamp":"2024-07-16T21:27:42.815040239Z","signature":"cAY37/xfrxZgXAkdexiYS4JK5ba4bL80wLmAKiFvLm8yHt8nrzDZr2qVwTJ8stZWOmKCXlV5ZmQ98IpSNjvKCw=="},{"block_id_flag":2,"validator_address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","timestamp":"2024-07-16T21:27:42.718637841Z","signature":"+aeq5mkuWxDlGqzSzYJ0VDdiRggUG9WeykSKnRw8LRcm6GSsOiDF5bJYEmSZZvxRWhmMAJVH+nWegnI5YRdPDQ=="},{"block_id_flag":2,"validator_address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","timestamp":"2024-07-16T21:27:42.674844126Z","signature":"c/IrK2Waqe+22/i9cJ84Grp6MYxloBy09VCH2o80nL5adl+FRYWZzmNz4dakjeWfgCQ52gBEQh35yy+64Yp5DA=="},{"block_id_flag":2,"validator_address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","timestamp":"2024-07-16T21:27:42.8464723Z","signature":"6Jek20gZ+1YeRylo+rquS1LUKKfraYbqKkExpLS7lcGacx4kDLg4qmSaY3+fm5Dmo+fUSNse08D3qj2JmuIeDw=="},{"block_id_flag":2,"validator_address":"4A3918A6D02D25290B243A86618071374FADD87B","timestamp":"2024-07-16T21:27:42.627613636Z","signature":"5j0q5BIdj1sil7nh8eWZe5p0TZ4Go4Dh18P27Ykyi9W0ceLmzupoiGy9dI5h2A8dpysLD30vnieTV0iNPNx4BA=="},{"block_id_flag":2,"validator_address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","timestamp":"2024-07-16T21:27:42.668259078Z","signature":"p3YA4xn9SV5YFVK8NQH7RXoMfEYJn2NFJA0fpYuv1YvT1Z/MmzSyGdvRnJICxGQfRH+TxoAJOCQlv+nqquGpAQ=="},{"block_id_flag":2,"validator_address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","timestamp":"2024-07-16T21:27:42.87798495Z","signature":"liVlEw4yygy3idGY41gIuBzDJrYR/utzLQ3LcAPmrQmnBmtBcoi6aGx1zWcWf52cOeXHSPYMdCPkx8aeCDZNCA=="},{"block_id_flag":2,"validator_address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","timestamp":"2024-07-16T21:27:43.039405455Z","signature":"ulyBK6y2Q/Rx4FqNaGUjXvv5kWyAW1Yi1DYlzMHjbOehQLkPaDThP5vKyVBCBb7RjKH1BQedRyCEcnhIIwzbDA=="},{"block_id_flag":2,"validator_address":"2131A959A819C085AFA86E560D5EC0DF1D632827","timestamp":"2024-07-16T21:27:42.748584137Z","signature":"VR/MRzaOExmn2okyCrIehx6F5KZ7tyIoQdkVU+X9PzXY0+QOcKKPV0vjLQAbvBjG7COLqmwuJO8OCoLD+92SBA=="},{"block_id_flag":2,"validator_address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","timestamp":"2024-07-16T21:27:42.633781846Z","signature":"Stz2eNqqpdEoElLoLCoUxKu48XyprThIilLaNdErmttMwhWoemZJMWFIZZ9T1G8gHKCvaNe+7+KHvamVQHPbDQ=="},{"block_id_flag":2,"validator_address":"F7A4EEF357935737058F08804DE4DD03144E960D","timestamp":"2024-07-16T21:27:42.683973642Z","signature":"PbnHGFpVlepTi5X3P/ARUVh+TJoh5aYlExhno14nf8YNg8qvMYmZAlUQgw6UVtJJpCNpf/EFzK7/pajTjpKMCw=="},{"block_id_flag":2,"validator_address":"0A957E96258B8BC5669C9A4DA146532C93E99242","timestamp":"2024-07-16T21:27:42.85109081Z","signature":"AWwilVhEMxDlOPkpR73u4jI6x6+ox9q7zWzmAH4ymdnyio9rm9TqA7R/wUee+lTaeCG0+2pxMs9h0aMaBLP2Dw=="},{"block_id_flag":2,"validator_address":"B07503589534AAAAD60836B33245410AD11CCEB9","timestamp":"2024-07-16T21:27:42.830991037Z","signature":"pjGW/lPycsJyN/uzUbWtJPKdI/nQo6a9mLBxfq7DzXEUFG6xBbr3/4Ne0bkx+c46Z9LhRfDKu604pMZ7A+JZDQ=="},{"block_id_flag":2,"validator_address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","timestamp":"2024-07-16T21:27:42.755476369Z","signature":"VcJZSqIPlpmfkA7GBtZBTGNGCJuNPDdXelDH5TEZw/5qCLpkPWYnuIye3kYl2gTT/ppY1lXzS3+O9TxeHOrvCg=="},{"block_id_flag":2,"validator_address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","timestamp":"2024-07-16T21:27:42.635871409Z","signature":"NeM/tmLHyBGMDwwCTP9BepmeHlcbGgBdyj1qmJQBIPCZVZgayQR4PKDhBFUl7O2y4fUV0Xcr1aR8YAzi1UFYAQ=="},{"block_id_flag":2,"validator_address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","timestamp":"2024-07-16T21:27:42.583667893Z","signature":"wuXfDO8iZB+woqK0Q85sZvyaAqtVduG5mcDctu/yaJzRBJJupG+sonkXOUbu8zJ2nh+I9TmOAKNTZ+flT2UvDw=="},{"block_id_flag":2,"validator_address":"F6D5482C2405A9844A1EB215148387AD18800D32","timestamp":"2024-07-16T21:27:42.679315572Z","signature":"Qm8aCWytX3xgyxR/ure1565Lk/f5dMvchvcbumazjM6ZnWvDZwuiN4t/dkSKnMskI+0hYUB16F5YuUTQFViuCQ=="},{"block_id_flag":2,"validator_address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","timestamp":"2024-07-16T21:27:43.042595371Z","signature":"h//ym+Q998/Z4BQS9FU39tJJDQy1xup+IJBl7ooUDFykRwHbA9TJAQpTptr/acfxFrCFpm9wNcPnebK1Wd2pAw=="},{"block_id_flag":2,"validator_address":"50922F9E58F64B3A219887F67117E4CF714AF490","timestamp":"2024-07-16T21:27:42.65924118Z","signature":"vcEq8XYjKtp6gzWkCNplDMINF8/FhVGplpd8Fve731asCQC6L+asO+tqq12QO7kj1HaaikitCrM5aVQQ4/IwCg=="},{"block_id_flag":2,"validator_address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","timestamp":"2024-07-16T21:27:42.760201195Z","signature":"f7zAl2BDRtHxUS2cRx1ixwQ1Nz1aMbKTCBtyhYBL6VYojqSBMj/LGirVIylQLfDosIwMPFyosuKh/W5D3zrOAQ=="},{"block_id_flag":2,"validator_address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","timestamp":"2024-07-16T21:27:42.809612062Z","signature":"ZhJEjrDKVHzGurKmNTBsNTKeaEUbM+eYLWvBWe8dyR3P7EQZAZe8QReMnHv4xToXPjtSCCAI77LR97va3RfPCA=="},{"block_id_flag":2,"validator_address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","timestamp":"2024-07-16T21:27:42.661590996Z","signature":"0La8rNK05xdFrpAFCb8K12fei7w9YVrjWLzVo8TIrHxAhzyRd0jgPg7IR0uRhspwyNKYFOC3GXNfGrl66imzDQ=="},{"block_id_flag":2,"validator_address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","timestamp":"2024-07-16T21:27:42.69782694Z","signature":"7hs3yizgokm9Ziw9kIBhfrec2zjRVJL05lwD8X3IkKvOWQoR5z6O6L11IfUido2lnGdxbXWjisChO6rsdTZWBQ=="},{"block_id_flag":2,"validator_address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","timestamp":"2024-07-16T21:27:42.699975594Z","signature":"dXlPPQQLGnitjjjtvy6nAmt+yDbnOP31RTnTFQQZmHaUJ1tkb7AeUcdG2yn8Nt5cj0TezKFJ3JyL2NFydwUzCA=="},{"block_id_flag":2,"validator_address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","timestamp":"2024-07-16T21:27:42.707716624Z","signature":"D9z5Ive4H0WnIdbPpo9HT2rQ9pUKlWCXfOafcUk1GLouubKF8MzbtNZfIc7oD1cYa9HIWzTx2m0T3u62imHiAQ=="}]}},"validator_set":{"validators":[{"address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"l/qNaf4JDxnhP+6Pf+2OSAJYksSIkjyefYCDvZPoahA="},"power":"74052443","name":null},{"address":"762CBA617226A799D898F134DD12661C7F1129EB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE="},"power":"70555622","name":null},{"address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","pub_key":{"type":"tendermint/PubKeyEd25519","value":"njq3L6yQabWMjmh9QjBobp2XOdNytaLPoxFgY2Qd3i8="},"power":"64650439","name":null},{"address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","pub_key":{"type":"tendermint/PubKeyEd25519","value":"259mAZKhNLksTkJ7qJZf+ZreaPMQtBY7NDeslqPRa9o="},"power":"28001060","name":null},{"address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J8wAKpZrD9kRbewJDMLQAuYkYNh33PhCg+wcdVcGxIw="},"power":"27553991","name":null},{"address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D3wP4IWMZcMt9UHVzFP2J19FDCP/732nvtT/f3CIatQ="},"power":"25298561","name":null},{"address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"2XKroLDmwSjW8Z0ZadGF/Co/6Bo5OreNldOxj9fl/Ww="},"power":"25000168","name":null},{"address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3rvnDucNb0+ZSdhfQSzjdFSFiZWUGerlEt4hp1EyHKM="},"power":"25000019","name":null},{"address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","pub_key":{"type":"tendermint/PubKeyEd25519","value":"UEKnFx4sn4K1aIPxrCu4zE3+Vr4vMGgIeu2iFAQsUH8="},"power":"24714090","name":null},{"address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"i/Zow0IiKpVFWRNxOwN+Fqe9zVj9VY+Pn8+YsuSo9/E="},"power":"4066863","name":null},{"address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"B6H09N1cxmSXGgqTuAIphe7ESJsCj687/8CYiKBTh4w="},"power":"4050758","name":null},{"address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4TpozS4FflJmfBg3MYhLw12UeVUSELod0fdnX4tAQgs="},"power":"4048910","name":null},{"address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LSpewjhpxXBs00/L2L6DQJabXcSoTzmjqZNTIw5DSCg="},"power":"4048857","name":null},{"address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"SfFXATPCbIeRUsb9RP+BfdYOH0v7H2aGbPGx1HlR1I0="},"power":"4030218","name":null},{"address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5QOLCS5zoZZGk7ZXnaU883fSQAhwneIvP98XcjOte8="},"power":"4023467","name":null},{"address":"9079C978817165244C051EFCE5AD163AAA905C6F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"fODnMY6gDPpnDlAsSQ2b6M5u3gjYNaKq1JL6LBFShzM="},"power":"4009700","name":null},{"address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jqBYsfBjFJhudulObGgaMawaeccpj+21nfs+Px6oNIY="},"power":"4002311","name":null},{"address":"11637B088406D4F3EFF52F2230C8068D230C7611","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gcI3uuOTA3ZAVCMsLawhjUt7cZc/EBJeipq9XGavEsg="},"power":"4002024","name":null},{"address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wdZ6voJ0Kdh/iJvnzjS9oAiSRtr7A2S4mifU3xFfEXk="},"power":"4001100","name":null},{"address":"BB408FA902A7B6A938C788957B2A874153261EC5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7rE47Ol0HqaZhnQQqlx5BD8rNGv6yTcRQANXtMY7y4g="},"power":"4001076","name":null},{"address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zj5o33wP8tFPM8qgoC4upsLQvrAc/DGT2J4JG+LhOJ4="},"power":"4001057","name":null},{"address":"F005689992F73B55B537461AC0AE0DF9694B36CF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"KgescyXaO/6YrE/GIuqmFdP0xXTqHUflMAH40HDm/20="},"power":"4000714","name":null},{"address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LKwKvQPVTwxwW4UDpyIvGW8Sa9sUdaxhhhVdOigrEyA="},"power":"4000566","name":null},{"address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ony9i2cN/h1wawOv0WN6Ql/9lDjDeLgOVCl1fRtuyDI="},"power":"4000504","name":null},{"address":"98271A1B3690F4EC867C760DBCA3754684F485AC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"k3zGTt9YVhopwi6iL+f/XYSj7cZRT+fcPlpwsojLsvg="},"power":"4000472","name":null},{"address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"feFjsaWtjmxYp6N+1r/9Lnd4o29skxSJclmebnk49Ao="},"power":"4000469","name":null},{"address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1QMroz50WA8c/IREfyr7Mm8S75gRCfuk0Ea4fokb4E="},"power":"4000103","name":null},{"address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ps6HB6/GSvuY4fKaszGLXMdHVk38ASzBcGBXeVVeDMo="},"power":"4000028","name":null},{"address":"28B6061D5E269B3585F019E1748E32CA9F34E739","pub_key":{"type":"tendermint/PubKeyEd25519","value":"CIc6ZcjHkdfYEzQqwXZBlYVTl13ZxAinYLLgHszHVgY="},"power":"4000012","name":null},{"address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"OKWb9Bw4pE6tfYtZiigi7A8ecGnCVBiJt2h1P7o1a7U="},"power":"4000008","name":null},{"address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jjLleXjmBwA66V5gejueapJUSYqb5W+oYSGXy/QLEQk="},"power":"4000007","name":null},{"address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RYrMwDTpJWv67sFVwKtmS+UxlN7hljKGWJqOsutcB1s="},"power":"3991125","name":null},{"address":"0DC59C626E4753D889DE2D3262A9A613E754668A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"1UlN1J5cR4XlFifpA8IA7A+xa3NQ1sJ/1IhssJQ+xEM="},"power":"3961059","name":null},{"address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ueUh8xh/b1zlBcCgblxHrZ9impMwKOkgyG5P3f1HkjE="},"power":"3961026","name":null},{"address":"346001263089D83465A72C6DB5EFBC32359111A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vdnWYA28lp43YkD0e2VExAcYPadTFh/Hpes0O0a4p20="},"power":"3960055","name":null},{"address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Fzeq1bTZn9T8Wev9O8/Huzs1nw/OXl0iTepDFRMUko8="},"power":"3960033","name":null},{"address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sAD409SvbABZBr0vCmjL6JK6XVQgQP4RM7v/Oiz/f88="},"power":"3957948","name":null},{"address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","pub_key":{"type":"tendermint/PubKeyEd25519","value":"27PwyrHHY/ndxqNrL6SdHomL4hR3JAJ5QMdQFYRlS9I="},"power":"3881201","name":null},{"address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"a/BQji6ozSlxXzMhtW4RGybuZ81s6tQKSPhO2mGIU4c="},"power":"3000010","name":null},{"address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dO71IfBvwwwJ6cEzc9oT1FqU0CUdckJV5F53kDYb22o="},"power":"2000006","name":null},{"address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D9iPx6VTH+xeewFFWfnI+a7dM6Y5Y9h/5S4WHro5wUQ="},"power":"1003008","name":null},{"address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"BRvI8B8k+QrDeOgdBNb7mLCbNEMatJNqDyZttdGtQm0="},"power":"1001309","name":null},{"address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"VXn41Fko8YeJ3vVvYy/yUtqfVbCv7FTivuDclSrw5Pc="},"power":"1000893","name":null},{"address":"E309A8AFFF70D04126D04BB53071B6020580D104","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J0kLUI0gmvWfWvzoxHaqwzXF3+VARlAIMGCRfB6Yj8A="},"power":"1000210","name":null},{"address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gN5Cln7uU3AVQYzT3QGgggv/3aN+eIewd6m5OfPpkTs="},"power":"1000042","name":null},{"address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","pub_key":{"type":"tendermint/PubKeyEd25519","value":"F3RJktKCIoDGEBWXgpDl2+LgNbq5X0rS8eXnY+i3aIY="},"power":"1000038","name":null},{"address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oRz4ydtLca6+HfffYIRv0PCsTm4xKBdYpx85lisMWng="},"power":"1000037","name":null},{"address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oYhHHoROhbAIzOuST8Qyua7O611uIr3NT2yyibK5x7Y="},"power":"1000020","name":null},{"address":"88731522401F260D5C253222CF6EF71586A192D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"m9gm7H1kmxvPzyo5ubgkmqKGQbJFHst9My51FLe2HeM="},"power":"1000009","name":null},{"address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cPgsoC0NIVUAe42qmzfbrLaznvYZCh1z92Q35D0KZOc="},"power":"990479","name":null},{"address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"PRXS/zL6clsHN2Srl49mRV+W+eL/g7DgY1MG8eu/8K8="},"power":"990174","name":null},{"address":"5769499735A69F335467D419764A69FAFFE29607","pub_key":{"type":"tendermint/PubKeyEd25519","value":"HnEoblS3w9JRSFqXX/2RCippz7tQD/ShYts+tGHoSBM="},"power":"980425","name":null},{"address":"113388853F11E28044A4ED3B11DF745D00D709CD","pub_key":{"type":"tendermint/PubKeyEd25519","value":"61X0w6XUKooaWi4FYzZghd6kJDIFFifK+EpMJWTHSaI="},"power":"509044","name":null},{"address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ba80uJncfcmlWoFM/AlzMI6Mut7SyDJTpbNV8kwMXl0="},"power":"502561","name":null},{"address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Y0SMVwQK9FHbFi7ykZSwah3TG56saeI0uTMXYvyb9dY="},"power":"501737","name":null},{"address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"EiSlqpx/n3VMPFtuTAa++axavjZ9yZzlTa3HtCz+lsI="},"power":"501375","name":null},{"address":"924090B949A3A3A43AEE52C4DAE342332C57B684","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cseuElK5A+VoeuKMvrm3AOTuzII46kf083lVMGpRLDo="},"power":"501271","name":null},{"address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QfqtiQS1sJXJKLIPYSoHTL1NtSfwm933fD1wOqgBxJI="},"power":"501058","name":null},{"address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5bxQwVfFqo0YqTMKMIn0Kmm5SR8QsYGps/x9CUtbFI="},"power":"501050","name":null},{"address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1EE0IXUX+xqvd08toyjMekOX1kNMzEmY2FLNe00sUg="},"power":"500841","name":null},{"address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Wblv9P9x2vItElCo/uoJGPVcB+bMOExuq+fE8+rVfrk="},"power":"500423","name":null},{"address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","pub_key":{"type":"tendermint/PubKeyEd25519","value":"N8ncRVbJpyffC98xo+mxWdqm/GamCJkVTB0YeM8gwkg="},"power":"500401","name":null},{"address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","pub_key":{"type":"tendermint/PubKeyEd25519","value":"GzwPkML4PmjOdcTvr2pm6rjO7cBHrckZR3oe2w4E+FA="},"power":"500018","name":null},{"address":"D5CABF35D9C01401B32540F938BE59FA2B044067","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Bcsbz2eNu1HWCUW9IkzHCZ6ACMxf/sepz12Q8YCdUDM="},"power":"500014","name":null},{"address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","pub_key":{"type":"tendermint/PubKeyEd25519","value":"tF609cLwhEnpi3W93lYIxE1sG/VLbvFKRX0wOzAQxeg="},"power":"500009","name":null},{"address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gmdjSSfvgwXEAJ7CEMDH0Tv+cQSEFujwSIFdR87tWZA="},"power":"500006","name":null},{"address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MJlbI1M3aILcOMSigyPMolCpjfQPzEsagrtZTN+9z6E="},"power":"500005","name":null},{"address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DE8/atJOsW6TA3iDRklz5DdI8j3Tx95o0nOhwkbkvBQ="},"power":"500001","name":null},{"address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zv4/6wZv5pwxuovxaC72oHNW0TAfiH/N+vsilZfiyHc="},"power":"500001","name":null},{"address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vYKrsdaWTO7YnMgWoUGWKO+A3XwgvXYoB+HNVjBkWAA="},"power":"500001","name":null},{"address":"E5183117268691950E77D53340C23857662CC908","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4k08zQEeKnu5auA0Zp3h5xfNfS6K5LfcN0vnAhNiyz8="},"power":"500001","name":null},{"address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"8yHvjPOugBmpP/D0FOfdpQ6oyiymtS1J+U3lNC/d/2U="},"power":"500001","name":null},{"address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"w5YcK+X1Uv6NVRKzY+4qaSw+Zum8CNDVC0+ip0NpQ5s="},"power":"496178","name":null},{"address":"633744F3BE877E6DF590E72E99425BA653156B93","pub_key":{"type":"tendermint/PubKeyEd25519","value":"rD+6Hqi0NsOsZgsjRAP2BbNtxWcieiDmmh3tng63xDQ="},"power":"495995","name":null},{"address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XuXuQxuSJIdpW49/wAalXxyjvuV1aGlamnpg+PDyu/A="},"power":"476704","name":null},{"address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ps7NCfnD+Nkvkgp8mtnh1S57i5OvVKymdrW1RDktbHk="},"power":"201075","name":null},{"address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wXe92Kj6b2uv5WP2yMffYDJ7naD3T08jneI8tQuohIM="},"power":"107519","name":null},{"address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","pub_key":{"type":"tendermint/PubKeyEd25519","value":"qgVzfy4FKDxIrJ/S0a31SHRL1OJZzsxkGMVEW8flsAs="},"power":"105245","name":null},{"address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Dq8TpiZCrf3fzg/sbMm6Ae5Ty3V1WPEtf1lKqFXVBU8="},"power":"102441","name":null},{"address":"4A3918A6D02D25290B243A86618071374FADD87B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"nuKCeeyYPNP/AwbavdBDum3sB8I7D4TCC4sFbPp7MPQ="},"power":"100448","name":null},{"address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XB08MBTE4Rsf3/11MNd+vtdzv0xTvKzGc+7/28Z4En4="},"power":"100370","name":null},{"address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7CT5oKkYGXFByTi8glX/46KCivpVffTBvic6gQL61G0="},"power":"100301","name":null},{"address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oJEFTe9oP7psA7onwhzs/17uEYyVi0FDqEZs2/9mGzM="},"power":"100226","name":null},{"address":"2131A959A819C085AFA86E560D5EC0DF1D632827","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Tac4dLmlfr+reh8jMPLQTGXYUBvY1cp1NtN2y1zDuDA="},"power":"100215","name":null},{"address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","pub_key":{"type":"tendermint/PubKeyEd25519","value":"g/lPk5YCZBxUxlLNgf5qzQN//wwNhIE9HH9w3QX1pMA="},"power":"100162","name":null},{"address":"F7A4EEF357935737058F08804DE4DD03144E960D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"yfV2cDweDavOEDVNWtOYuHcwONDP4jyC/ZG8TUruRD4="},"power":"100136","name":null},{"address":"0A957E96258B8BC5669C9A4DA146532C93E99242","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dJdeXyHrKwqKAboLkSfsmvdQ+WRfYQTz+DbJQDeIFIs="},"power":"100130","name":null},{"address":"B07503589534AAAAD60836B33245410AD11CCEB9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"NVy8f5VLbLWBLrnWMeP+sIkt0iVW4Q3ESepiMx0+j4E="},"power":"100125","name":null},{"address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DP6+z/+64vbsAOx3O8Ej+C9iA572eU5nxlUfGoMB89M="},"power":"100121","name":null},{"address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ZhjOncfNrailm0sDSE0Om3wqYKL5w+QwBowGnkwzBrA="},"power":"100105","name":null},{"address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwSHuhiiooJGDeqHgh/cFoUudQv0zloyeiz400kyv8s="},"power":"100100","name":null},{"address":"F6D5482C2405A9844A1EB215148387AD18800D32","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MwxKwbDR+Pfj2kb8e/mnRy7gLw4n2oJA4qe/E8K6A5E="},"power":"100085","name":null},{"address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3IevyShLKCWeb5joXQjcpPDsvQWnk7bbHLqCd1td7sE="},"power":"100050","name":null},{"address":"50922F9E58F64B3A219887F67117E4CF714AF490","pub_key":{"type":"tendermint/PubKeyEd25519","value":"95WzrdnBvJzBBrOPjORQM0u/70LJnpyvZha6XAvS+T8="},"power":"100048","name":null},{"address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7d0Y9SKn6bfYtn1J9buGsXImkkPHl/bQX8gI7J6Grjk="},"power":"100045","name":null},{"address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"kWIFV6puc+0TvyMPwreUkcAJFHANXbWoLGcTJEDLQPQ="},"power":"100014","name":null},{"address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","pub_key":{"type":"tendermint/PubKeyEd25519","value":"9FusyXhw+gECqAjvHefpCpSS+KQ/fDltXWFy+5HfPcE="},"power":"100011","name":null},{"address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwJhFD9crCT0jEcZi7TXYGo5/tLfRrFGb9C5EYDlHRo="},"power":"100011","name":null},{"address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"WCwJZKhAwYmOH4Eo5TXvsS9W8KqEx1Oi8mj/gfyuQic="},"power":"100011","name":null},{"address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sJQZYhdp6x/l6MQ40Pj2880J6Q/t3433EZglkk1yYaA="},"power":"100010","name":null}],"proposer":null,"total_voting_power":"511862423"},"next_validator_set":{"validators":[{"address":"7619BFC85B72E319BF414A784D4DE40EE9B92C16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"l/qNaf4JDxnhP+6Pf+2OSAJYksSIkjyefYCDvZPoahA="},"power":"74052443","name":null},{"address":"762CBA617226A799D898F134DD12661C7F1129EB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"6bdjjKHELaN9colwYy/ad+xh3MUgOVq106ZFucK46LE="},"power":"70555622","name":null},{"address":"597944BC0AEDFA1D9DA7C2098FB05D7B6A2D4946","pub_key":{"type":"tendermint/PubKeyEd25519","value":"njq3L6yQabWMjmh9QjBobp2XOdNytaLPoxFgY2Qd3i8="},"power":"64650439","name":null},{"address":"7744C8CE6E06E67AB9721696AA752B951C93E9E0","pub_key":{"type":"tendermint/PubKeyEd25519","value":"259mAZKhNLksTkJ7qJZf+ZreaPMQtBY7NDeslqPRa9o="},"power":"28001060","name":null},{"address":"8FBEF0DBAAE51D918F9ABFD96653F4932171870E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J8wAKpZrD9kRbewJDMLQAuYkYNh33PhCg+wcdVcGxIw="},"power":"27553991","name":null},{"address":"0B76107110A486E8767FA1997EA0C4B40B7851AF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D3wP4IWMZcMt9UHVzFP2J19FDCP/732nvtT/f3CIatQ="},"power":"25298561","name":null},{"address":"D6E25B7E6E6C96D1B7135CF41FF03DF84DE2BA2C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"2XKroLDmwSjW8Z0ZadGF/Co/6Bo5OreNldOxj9fl/Ww="},"power":"25000168","name":null},{"address":"59158C19ED4DF57D59B54F80B07C0AFB37DAFF0D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3rvnDucNb0+ZSdhfQSzjdFSFiZWUGerlEt4hp1EyHKM="},"power":"25000019","name":null},{"address":"91AB27CC321622AC4DC778D2F1FE367CFADAC665","pub_key":{"type":"tendermint/PubKeyEd25519","value":"UEKnFx4sn4K1aIPxrCu4zE3+Vr4vMGgIeu2iFAQsUH8="},"power":"24714090","name":null},{"address":"C822706DA92B375B6793FEC5FCAD04BB5AFE142A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"i/Zow0IiKpVFWRNxOwN+Fqe9zVj9VY+Pn8+YsuSo9/E="},"power":"4066863","name":null},{"address":"FF73CE6FE36E313684457C855D7D25198B87C8A6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"B6H09N1cxmSXGgqTuAIphe7ESJsCj687/8CYiKBTh4w="},"power":"4050758","name":null},{"address":"E1F1D0F31F8DB86B829C8502AD1F6F1576C08A6D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4TpozS4FflJmfBg3MYhLw12UeVUSELod0fdnX4tAQgs="},"power":"4048910","name":null},{"address":"13E610C20C1C6623A3C32AC058E9F8E76BBEEC16","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LSpewjhpxXBs00/L2L6DQJabXcSoTzmjqZNTIw5DSCg="},"power":"4048857","name":null},{"address":"EE927F115AD4FD4BC131CA311D332ADDAC62CCAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"SfFXATPCbIeRUsb9RP+BfdYOH0v7H2aGbPGx1HlR1I0="},"power":"4030218","name":null},{"address":"97C24BFDC996F0BF40FDDA96CC22D417D0B8D0BA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5QOLCS5zoZZGk7ZXnaU883fSQAhwneIvP98XcjOte8="},"power":"4023467","name":null},{"address":"9079C978817165244C051EFCE5AD163AAA905C6F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"fODnMY6gDPpnDlAsSQ2b6M5u3gjYNaKq1JL6LBFShzM="},"power":"4009700","name":null},{"address":"7EC8ADD79B454AC37625077453DF49FAC1BFD7E1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jqBYsfBjFJhudulObGgaMawaeccpj+21nfs+Px6oNIY="},"power":"4002311","name":null},{"address":"11637B088406D4F3EFF52F2230C8068D230C7611","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gcI3uuOTA3ZAVCMsLawhjUt7cZc/EBJeipq9XGavEsg="},"power":"4002024","name":null},{"address":"52E55D04CCD1C78D4FC520FE17AE4584FA2053A8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wdZ6voJ0Kdh/iJvnzjS9oAiSRtr7A2S4mifU3xFfEXk="},"power":"4001100","name":null},{"address":"BB408FA902A7B6A938C788957B2A874153261EC5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7rE47Ol0HqaZhnQQqlx5BD8rNGv6yTcRQANXtMY7y4g="},"power":"4001076","name":null},{"address":"8C55B13AEE44C518E363DD328E2AB451D6569EAC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zj5o33wP8tFPM8qgoC4upsLQvrAc/DGT2J4JG+LhOJ4="},"power":"4001057","name":null},{"address":"F005689992F73B55B537461AC0AE0DF9694B36CF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"KgescyXaO/6YrE/GIuqmFdP0xXTqHUflMAH40HDm/20="},"power":"4000714","name":null},{"address":"01458B61F0D7DE6E90798FE8C370413D718EB34C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"LKwKvQPVTwxwW4UDpyIvGW8Sa9sUdaxhhhVdOigrEyA="},"power":"4000566","name":null},{"address":"5AF159B8269B974F9274DAEA0F778ADD3B12707D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ony9i2cN/h1wawOv0WN6Ql/9lDjDeLgOVCl1fRtuyDI="},"power":"4000504","name":null},{"address":"98271A1B3690F4EC867C760DBCA3754684F485AC","pub_key":{"type":"tendermint/PubKeyEd25519","value":"k3zGTt9YVhopwi6iL+f/XYSj7cZRT+fcPlpwsojLsvg="},"power":"4000472","name":null},{"address":"969B1B7DCAFA313131620AC163E3A09A03B49BE6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"feFjsaWtjmxYp6N+1r/9Lnd4o29skxSJclmebnk49Ao="},"power":"4000469","name":null},{"address":"4D5B4C1A687B13AAD96F9CED90F006DFF03CEC45","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1QMroz50WA8c/IREfyr7Mm8S75gRCfuk0Ea4fokb4E="},"power":"4000103","name":null},{"address":"3BFE2EF588102F19F40952DDDD3A89BA90D7351F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ps6HB6/GSvuY4fKaszGLXMdHVk38ASzBcGBXeVVeDMo="},"power":"4000028","name":null},{"address":"28B6061D5E269B3585F019E1748E32CA9F34E739","pub_key":{"type":"tendermint/PubKeyEd25519","value":"CIc6ZcjHkdfYEzQqwXZBlYVTl13ZxAinYLLgHszHVgY="},"power":"4000012","name":null},{"address":"C8C62F1CF89BF5E852E252ED38CBA4A64787CF1B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"OKWb9Bw4pE6tfYtZiigi7A8ecGnCVBiJt2h1P7o1a7U="},"power":"4000008","name":null},{"address":"70A191EF78A0C8B9B69E005A685B064C254B1F33","pub_key":{"type":"tendermint/PubKeyEd25519","value":"jjLleXjmBwA66V5gejueapJUSYqb5W+oYSGXy/QLEQk="},"power":"4000007","name":null},{"address":"38CECDD91DAE3D8F536C080742A69FEBB6EFDBFF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RYrMwDTpJWv67sFVwKtmS+UxlN7hljKGWJqOsutcB1s="},"power":"3991125","name":null},{"address":"0DC59C626E4753D889DE2D3262A9A613E754668A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"1UlN1J5cR4XlFifpA8IA7A+xa3NQ1sJ/1IhssJQ+xEM="},"power":"3961059","name":null},{"address":"1E7BA20AACF7EF2CDEA41CDFF8DCEDFBCF12F363","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ueUh8xh/b1zlBcCgblxHrZ9impMwKOkgyG5P3f1HkjE="},"power":"3961026","name":null},{"address":"346001263089D83465A72C6DB5EFBC32359111A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vdnWYA28lp43YkD0e2VExAcYPadTFh/Hpes0O0a4p20="},"power":"3960055","name":null},{"address":"2F334E80D3EA0AE019D6498D8DD7E0EC472E5424","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Fzeq1bTZn9T8Wev9O8/Huzs1nw/OXl0iTepDFRMUko8="},"power":"3960033","name":null},{"address":"80726DCD4E975716843F213C7E5A36400ABCFDFE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sAD409SvbABZBr0vCmjL6JK6XVQgQP4RM7v/Oiz/f88="},"power":"3957948","name":null},{"address":"4520D7FA09B49EA0C0F39E6788E6EB3FD8065690","pub_key":{"type":"tendermint/PubKeyEd25519","value":"27PwyrHHY/ndxqNrL6SdHomL4hR3JAJ5QMdQFYRlS9I="},"power":"3881201","name":null},{"address":"93CCD84A7302F5676465A1239C2544AD3140D7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"a/BQji6ozSlxXzMhtW4RGybuZ81s6tQKSPhO2mGIU4c="},"power":"3000010","name":null},{"address":"3824438082C68B36ED8F5199155CD78ABBBDA30C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dO71IfBvwwwJ6cEzc9oT1FqU0CUdckJV5F53kDYb22o="},"power":"2000006","name":null},{"address":"9B2FB5ABCB3B0289D03AF5A8577C76D9A37A32D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"D9iPx6VTH+xeewFFWfnI+a7dM6Y5Y9h/5S4WHro5wUQ="},"power":"1003008","name":null},{"address":"87D1611F9BA8ABF12C13B32F90469977B4C94F9A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"BRvI8B8k+QrDeOgdBNb7mLCbNEMatJNqDyZttdGtQm0="},"power":"1001309","name":null},{"address":"5E9EE98A3CBD523D0D3C3518048DF8C322BB67D5","pub_key":{"type":"tendermint/PubKeyEd25519","value":"VXn41Fko8YeJ3vVvYy/yUtqfVbCv7FTivuDclSrw5Pc="},"power":"1000893","name":null},{"address":"E309A8AFFF70D04126D04BB53071B6020580D104","pub_key":{"type":"tendermint/PubKeyEd25519","value":"J0kLUI0gmvWfWvzoxHaqwzXF3+VARlAIMGCRfB6Yj8A="},"power":"1000210","name":null},{"address":"3B0F1CAEEB84A5AF239580FB26D6199CB17CEB3A","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gN5Cln7uU3AVQYzT3QGgggv/3aN+eIewd6m5OfPpkTs="},"power":"1000042","name":null},{"address":"14C590ADD4D238649F2CC7B198B52B8BDB63AC78","pub_key":{"type":"tendermint/PubKeyEd25519","value":"F3RJktKCIoDGEBWXgpDl2+LgNbq5X0rS8eXnY+i3aIY="},"power":"1000038","name":null},{"address":"682EF7D2FB487050D6AD71173FCC7C983B031A4B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oRz4ydtLca6+HfffYIRv0PCsTm4xKBdYpx85lisMWng="},"power":"1000037","name":null},{"address":"BEEE6DB44A01D8005CD59904F9AEE12BE9DBA6A3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oYhHHoROhbAIzOuST8Qyua7O611uIr3NT2yyibK5x7Y="},"power":"1000020","name":null},{"address":"88731522401F260D5C253222CF6EF71586A192D3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"m9gm7H1kmxvPzyo5ubgkmqKGQbJFHst9My51FLe2HeM="},"power":"1000009","name":null},{"address":"CD10B5095AC4541972E0C0FDE35A39CF92A040DA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cPgsoC0NIVUAe42qmzfbrLaznvYZCh1z92Q35D0KZOc="},"power":"990479","name":null},{"address":"469CB700B5C1D9DE8905457AE5A7BD7E3FCB75EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"PRXS/zL6clsHN2Srl49mRV+W+eL/g7DgY1MG8eu/8K8="},"power":"990174","name":null},{"address":"5769499735A69F335467D419764A69FAFFE29607","pub_key":{"type":"tendermint/PubKeyEd25519","value":"HnEoblS3w9JRSFqXX/2RCippz7tQD/ShYts+tGHoSBM="},"power":"980425","name":null},{"address":"113388853F11E28044A4ED3B11DF745D00D709CD","pub_key":{"type":"tendermint/PubKeyEd25519","value":"61X0w6XUKooaWi4FYzZghd6kJDIFFifK+EpMJWTHSaI="},"power":"509044","name":null},{"address":"D92E949735CFD958FE2E1EA2F7ACCFBC981059B4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ba80uJncfcmlWoFM/AlzMI6Mut7SyDJTpbNV8kwMXl0="},"power":"502561","name":null},{"address":"F271741FA4B163F3204A5BC2570E74F146AA33D9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Y0SMVwQK9FHbFi7ykZSwah3TG56saeI0uTMXYvyb9dY="},"power":"501737","name":null},{"address":"B790E6ABE58DB7122F81FF52F7B2183AEEC41D6C","pub_key":{"type":"tendermint/PubKeyEd25519","value":"EiSlqpx/n3VMPFtuTAa++axavjZ9yZzlTa3HtCz+lsI="},"power":"501375","name":null},{"address":"924090B949A3A3A43AEE52C4DAE342332C57B684","pub_key":{"type":"tendermint/PubKeyEd25519","value":"cseuElK5A+VoeuKMvrm3AOTuzII46kf083lVMGpRLDo="},"power":"501271","name":null},{"address":"6BB3BE6A41922712373BBCBA647B3A1486CF56B7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QfqtiQS1sJXJKLIPYSoHTL1NtSfwm933fD1wOqgBxJI="},"power":"501058","name":null},{"address":"C8E66B2FB198544C40058986AFF7BFD9B1FD6442","pub_key":{"type":"tendermint/PubKeyEd25519","value":"h5bxQwVfFqo0YqTMKMIn0Kmm5SR8QsYGps/x9CUtbFI="},"power":"501050","name":null},{"address":"9AD672973AF0C5A606F1D2EE0F261AF5DD61DACE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"y1EE0IXUX+xqvd08toyjMekOX1kNMzEmY2FLNe00sUg="},"power":"500841","name":null},{"address":"3511B17D31452B433E1392C75CC1D9A57FB769EE","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Wblv9P9x2vItElCo/uoJGPVcB+bMOExuq+fE8+rVfrk="},"power":"500423","name":null},{"address":"6C6F50C1E0E2A69BFC2AB7DABE0A3F091D17E666","pub_key":{"type":"tendermint/PubKeyEd25519","value":"N8ncRVbJpyffC98xo+mxWdqm/GamCJkVTB0YeM8gwkg="},"power":"500401","name":null},{"address":"0FDB40C1B3ED17E49061B1F577393E5B91323C99","pub_key":{"type":"tendermint/PubKeyEd25519","value":"GzwPkML4PmjOdcTvr2pm6rjO7cBHrckZR3oe2w4E+FA="},"power":"500018","name":null},{"address":"D5CABF35D9C01401B32540F938BE59FA2B044067","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Bcsbz2eNu1HWCUW9IkzHCZ6ACMxf/sepz12Q8YCdUDM="},"power":"500014","name":null},{"address":"D6DFC3CD8487061C9612E5E42924FC4E5F622E23","pub_key":{"type":"tendermint/PubKeyEd25519","value":"tF609cLwhEnpi3W93lYIxE1sG/VLbvFKRX0wOzAQxeg="},"power":"500009","name":null},{"address":"F17C3F91E8237C9AE2806625904E8639AC9A3EA7","pub_key":{"type":"tendermint/PubKeyEd25519","value":"gmdjSSfvgwXEAJ7CEMDH0Tv+cQSEFujwSIFdR87tWZA="},"power":"500006","name":null},{"address":"2A8FB5C0567D3031B6A26243BF9F3D04E706548D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MJlbI1M3aILcOMSigyPMolCpjfQPzEsagrtZTN+9z6E="},"power":"500005","name":null},{"address":"1FEECDA6D9268908A1F84093F0F888F2F752A212","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DE8/atJOsW6TA3iDRklz5DdI8j3Tx95o0nOhwkbkvBQ="},"power":"500001","name":null},{"address":"2B4F222E08213F7F6839E0B2D85C0F56675BD2AB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Zv4/6wZv5pwxuovxaC72oHNW0TAfiH/N+vsilZfiyHc="},"power":"500001","name":null},{"address":"C97A18C41B44DFC2F5FA1FCF8BC1BCFF5E649AE8","pub_key":{"type":"tendermint/PubKeyEd25519","value":"vYKrsdaWTO7YnMgWoUGWKO+A3XwgvXYoB+HNVjBkWAA="},"power":"500001","name":null},{"address":"E5183117268691950E77D53340C23857662CC908","pub_key":{"type":"tendermint/PubKeyEd25519","value":"4k08zQEeKnu5auA0Zp3h5xfNfS6K5LfcN0vnAhNiyz8="},"power":"500001","name":null},{"address":"EF8D6E39A9AA29C04D9D4F0F43EDAD5AB06F56F3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"8yHvjPOugBmpP/D0FOfdpQ6oyiymtS1J+U3lNC/d/2U="},"power":"500001","name":null},{"address":"E01B694AFE5D64691341E931A80ACF9D95E6C8C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"w5YcK+X1Uv6NVRKzY+4qaSw+Zum8CNDVC0+ip0NpQ5s="},"power":"496178","name":null},{"address":"633744F3BE877E6DF590E72E99425BA653156B93","pub_key":{"type":"tendermint/PubKeyEd25519","value":"rD+6Hqi0NsOsZgsjRAP2BbNtxWcieiDmmh3tng63xDQ="},"power":"495995","name":null},{"address":"6A152D73CD9146A9C1DD4CF9FEF636E2235ECB7E","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XuXuQxuSJIdpW49/wAalXxyjvuV1aGlamnpg+PDyu/A="},"power":"476704","name":null},{"address":"CD34D386E534320153E1A3B02DEFB4CE0773E462","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ps7NCfnD+Nkvkgp8mtnh1S57i5OvVKymdrW1RDktbHk="},"power":"201075","name":null},{"address":"A601B7BCB5172E302329CF3DB6B0E975C8A21D10","pub_key":{"type":"tendermint/PubKeyEd25519","value":"wXe92Kj6b2uv5WP2yMffYDJ7naD3T08jneI8tQuohIM="},"power":"107519","name":null},{"address":"CBA82E0DF6C639D320AC0A421238F6EF93373C94","pub_key":{"type":"tendermint/PubKeyEd25519","value":"qgVzfy4FKDxIrJ/S0a31SHRL1OJZzsxkGMVEW8flsAs="},"power":"105245","name":null},{"address":"0D6EA92C96F4DA14C40B1CA7E2D82A811C9B2196","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Dq8TpiZCrf3fzg/sbMm6Ae5Ty3V1WPEtf1lKqFXVBU8="},"power":"102441","name":null},{"address":"4A3918A6D02D25290B243A86618071374FADD87B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"nuKCeeyYPNP/AwbavdBDum3sB8I7D4TCC4sFbPp7MPQ="},"power":"100448","name":null},{"address":"7BCC38AF8F5494F000D2B7B89EEB9D67B14A0F3F","pub_key":{"type":"tendermint/PubKeyEd25519","value":"XB08MBTE4Rsf3/11MNd+vtdzv0xTvKzGc+7/28Z4En4="},"power":"100370","name":null},{"address":"8536E9166685E936CAB4FBE1F3588F65623E9E81","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7CT5oKkYGXFByTi8glX/46KCivpVffTBvic6gQL61G0="},"power":"100301","name":null},{"address":"DC40C623F0EE6A10CC1E9134E9ADB955EDD319CA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"oJEFTe9oP7psA7onwhzs/17uEYyVi0FDqEZs2/9mGzM="},"power":"100226","name":null},{"address":"2131A959A819C085AFA86E560D5EC0DF1D632827","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Tac4dLmlfr+reh8jMPLQTGXYUBvY1cp1NtN2y1zDuDA="},"power":"100215","name":null},{"address":"A09C4BDCBE3718342A27BD9D420FD14C703C9965","pub_key":{"type":"tendermint/PubKeyEd25519","value":"g/lPk5YCZBxUxlLNgf5qzQN//wwNhIE9HH9w3QX1pMA="},"power":"100162","name":null},{"address":"F7A4EEF357935737058F08804DE4DD03144E960D","pub_key":{"type":"tendermint/PubKeyEd25519","value":"yfV2cDweDavOEDVNWtOYuHcwONDP4jyC/ZG8TUruRD4="},"power":"100136","name":null},{"address":"0A957E96258B8BC5669C9A4DA146532C93E99242","pub_key":{"type":"tendermint/PubKeyEd25519","value":"dJdeXyHrKwqKAboLkSfsmvdQ+WRfYQTz+DbJQDeIFIs="},"power":"100130","name":null},{"address":"B07503589534AAAAD60836B33245410AD11CCEB9","pub_key":{"type":"tendermint/PubKeyEd25519","value":"NVy8f5VLbLWBLrnWMeP+sIkt0iVW4Q3ESepiMx0+j4E="},"power":"100125","name":null},{"address":"5A806CC33FC21BCF9F2F47BE23B6586E04DED0D1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"DP6+z/+64vbsAOx3O8Ej+C9iA572eU5nxlUfGoMB89M="},"power":"100121","name":null},{"address":"967B6B5C64615DEB574D88C1F07F23F77E6E7EBA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ZhjOncfNrailm0sDSE0Om3wqYKL5w+QwBowGnkwzBrA="},"power":"100105","name":null},{"address":"2DC2EF8D1059A7A90E9D4AD35DC8F4F8CD7EB772","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwSHuhiiooJGDeqHgh/cFoUudQv0zloyeiz400kyv8s="},"power":"100100","name":null},{"address":"F6D5482C2405A9844A1EB215148387AD18800D32","pub_key":{"type":"tendermint/PubKeyEd25519","value":"MwxKwbDR+Pfj2kb8e/mnRy7gLw4n2oJA4qe/E8K6A5E="},"power":"100085","name":null},{"address":"473FB7626E52E54BD406A255DBA3B1822F8FC2EA","pub_key":{"type":"tendermint/PubKeyEd25519","value":"3IevyShLKCWeb5joXQjcpPDsvQWnk7bbHLqCd1td7sE="},"power":"100050","name":null},{"address":"50922F9E58F64B3A219887F67117E4CF714AF490","pub_key":{"type":"tendermint/PubKeyEd25519","value":"95WzrdnBvJzBBrOPjORQM0u/70LJnpyvZha6XAvS+T8="},"power":"100048","name":null},{"address":"E5C8264B472C5BD93BD9CA9CE99C221DE14B7EFB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"7d0Y9SKn6bfYtn1J9buGsXImkkPHl/bQX8gI7J6Grjk="},"power":"100045","name":null},{"address":"FE6AE5C0EE214D1A1199387B06F7783F66DBC09B","pub_key":{"type":"tendermint/PubKeyEd25519","value":"kWIFV6puc+0TvyMPwreUkcAJFHANXbWoLGcTJEDLQPQ="},"power":"100014","name":null},{"address":"26EFB42C96DBFA42D740333C33E2713AA050FA77","pub_key":{"type":"tendermint/PubKeyEd25519","value":"9FusyXhw+gECqAjvHefpCpSS+KQ/fDltXWFy+5HfPcE="},"power":"100011","name":null},{"address":"D87DA6AD5B598E723EE3A03BE0A6F9AB07EB0E01","pub_key":{"type":"tendermint/PubKeyEd25519","value":"lwJhFD9crCT0jEcZi7TXYGo5/tLfRrFGb9C5EYDlHRo="},"power":"100011","name":null},{"address":"E23A9173DF68A8BE51650807E55104E6101CA7CB","pub_key":{"type":"tendermint/PubKeyEd25519","value":"WCwJZKhAwYmOH4Eo5TXvsS9W8KqEx1Oi8mj/gfyuQic="},"power":"100011","name":null},{"address":"9E9F1F203A5AA77340B4BCE0472C3C24D3A061B3","pub_key":{"type":"tendermint/PubKeyEd25519","value":"sJQZYhdp6x/l6MQ40Pj2880J6Q/t3433EZglkk1yYaA="},"power":"100010","name":null}],"proposer":null,"total_voting_power":"511862423"},"provider":"726bc8d260387cf56ecfad3a6bf6fecd903e18a2"} \ No newline at end of file diff --git a/examples/tendermint/script/src/main.rs b/examples/tendermint/script/src/main.rs index 4184fadd0c..f243879876 100644 --- a/examples/tendermint/script/src/main.rs +++ b/examples/tendermint/script/src/main.rs @@ -1,40 +1,21 @@ use sp1_sdk::SP1ProofWithPublicValues; use std::time::Duration; -use tokio::runtime::Runtime; -use reqwest::Client; use sp1_sdk::{utils, ProverClient, SP1Stdin}; -use tendermint_light_client_verifier::options::Options; -use tendermint_light_client_verifier::types::LightBlock; -use tendermint_light_client_verifier::ProdVerifier; -use tendermint_light_client_verifier::Verdict; -use tendermint_light_client_verifier::Verifier; +use tendermint_light_client_verifier::{ + options::Options, types::LightBlock, ProdVerifier, Verdict, Verifier, +}; -use crate::util::fetch_latest_commit; -use crate::util::fetch_light_block; +use crate::util::load_light_block; const TENDERMINT_ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf"); + mod util; -async fn get_light_blocks() -> (LightBlock, LightBlock) { - // Uniquely identify a peer in the network. - let peer_id: [u8; 20] = [ - 0x72, 0x6b, 0xc8, 0xd2, 0x60, 0x38, 0x7c, 0xf5, 0x6e, 0xcf, 0xad, 0x3a, 0x6b, 0xf6, 0xfe, - 0xcd, 0x90, 0x3e, 0x18, 0xa2, - ]; - const BASE_URL: &str = "https://celestia-mocha-rpc.publicnode.com:443"; - let client = Client::new(); - let url = format!("{}/commit", BASE_URL); - let latest_commit = fetch_latest_commit(&client, &url).await.unwrap(); - let block: u64 = latest_commit.result.signed_header.header.height.into(); - println!("Latest block: {}", block); - let light_block_1 = fetch_light_block(2279100, peer_id, BASE_URL) - .await - .expect("Failed to generate light block 1"); - let light_block_2 = fetch_light_block(2279130, peer_id, BASE_URL) - .await - .expect("Failed to generate light block 2"); +fn get_light_blocks() -> (LightBlock, LightBlock) { + let light_block_1 = load_light_block(2279100).expect("Failed to generate light block 1"); + let light_block_2 = load_light_block(2279130).expect("Failed to generate light block 2"); (light_block_1, light_block_2) } @@ -42,9 +23,8 @@ fn main() { // Generate proof. utils::setup_logger(); - // Use tokio runtime to get the light blocks. - let rt = Runtime::new().unwrap(); - let (light_block_1, light_block_2) = rt.block_on(async { get_light_blocks().await }); + // Load light blocks from the `files` subdirectory + let (light_block_1, light_block_2) = get_light_blocks(); let expected_verdict = verify_blocks(light_block_1.clone(), light_block_2.clone()); @@ -63,6 +43,9 @@ fn main() { let client = ProverClient::new(); let (pk, vk) = client.setup(TENDERMINT_ELF); + + let execute = client.execute(TENDERMINT_ELF, stdin.clone()).run().expect("proving failed"); + let proof = client.prove(&pk, stdin).compressed().run().expect("proving failed"); // Verify proof. @@ -77,15 +60,12 @@ fn main() { assert_eq!(proof.public_values.as_ref(), expected_public_values); // Test a round trip of proof serialization and deserialization. - proof - .save("proof-with-pis.bin") - .expect("saving proof failed"); - let deserialized_proof = SP1ProofWithPublicValues::load("proof-with-pis.bin").expect("loading proof failed"); + proof.save("proof-with-pis.bin").expect("saving proof failed"); + let deserialized_proof = + SP1ProofWithPublicValues::load("proof-with-pis.bin").expect("loading proof failed"); // Verify the deserialized proof. - client - .verify(&deserialized_proof, &vk) - .expect("verification failed"); + client.verify(&deserialized_proof, &vk).expect("verification failed"); println!("successfully generated and verified proof for the program!") } diff --git a/examples/tendermint/script/src/util.rs b/examples/tendermint/script/src/util.rs index f60dfc1cef..2c3b0c9ef7 100644 --- a/examples/tendermint/script/src/util.rs +++ b/examples/tendermint/script/src/util.rs @@ -1,155 +1,17 @@ #![allow(dead_code)] -use std::collections::HashMap; use std::error::Error; -use reqwest::Client; -use serde::Deserialize; -use tendermint::{ - block::signed_header::SignedHeader, - node::Id, - validator::{Info, Set}, +use std::{ + fs::File, + io::Read, }; -use tendermint_light_client_verifier::types::{LightBlock, ValidatorSet}; -#[derive(Debug, Deserialize)] -pub struct CommitResponse { - pub result: SignedHeaderWrapper, -} - -#[derive(Debug, Deserialize)] -pub struct SignedHeaderWrapper { - pub signed_header: SignedHeader, -} - -#[derive(Debug, Deserialize)] -pub struct ValidatorSetResponse { - pub result: BlockValidatorSet, -} - -#[derive(Debug, Deserialize)] -pub struct BlockValidatorSet { - pub block_height: String, - pub validators: Vec, - pub count: String, - pub total: String, -} - -pub fn sort_signatures_by_validators_power_desc( - signed_header: &mut SignedHeader, - validators_set: &ValidatorSet, -) { - let validator_powers: HashMap<_, _> = validators_set - .validators() - .iter() - .map(|v| (v.address, v.power())) - .collect(); - - signed_header.commit.signatures.sort_by(|a, b| { - let power_a = a - .validator_address() - .and_then(|addr| validator_powers.get(&addr)) - .unwrap_or(&0); - let power_b = b - .validator_address() - .and_then(|addr| validator_powers.get(&addr)) - .unwrap_or(&0); - power_b.cmp(power_a) - }); -} - -pub async fn fetch_latest_commit( - client: &Client, - url: &str, -) -> Result> { - let response: CommitResponse = client - .get(url) - .send() - .await? - .json::() - .await?; - Ok(response) -} - -pub async fn fetch_commit( - client: &Client, - url: &str, - block_height: u64, -) -> Result> { - let response: CommitResponse = client - .get(url) - .query(&[ - ("height", block_height.to_string().as_str()), - ("per_page", "100"), // helpful only when fetching validators - ]) - .send() - .await? - .json::() - .await?; - Ok(response) -} - -pub async fn fetch_validators( - client: &Client, - url: &str, - block_height: u64, -) -> Result, Box> { - let mut validators = vec![]; - let mut collected_validators = 0; - let mut page_index = 1; - loop { - let response = client - .get(url) - .query(&[ - ("height", block_height.to_string().as_str()), - ("per_page", "100"), - ("page", page_index.to_string().as_str()), - ]) - .send() - .await? - .json::() - .await?; - let block_validator_set: BlockValidatorSet = response.result; - validators.extend(block_validator_set.validators); - collected_validators += block_validator_set.count.parse::().unwrap(); - - if collected_validators >= block_validator_set.total.parse::().unwrap() { - break; - } - page_index += 1; - } - - Ok(validators) -} - -pub async fn fetch_light_block( - block_height: u64, - peer_id: [u8; 20], - base_url: &str, -) -> Result> { - let client = Client::new(); - - let commit_response = - fetch_commit(&client, &format!("{}/commit", base_url), block_height).await?; - let mut signed_header = commit_response.result.signed_header; - - let validator_response = - fetch_validators(&client, &format!("{}/validators", base_url), block_height).await?; - - let validators = Set::new(validator_response, None); - - let next_validator_response = fetch_validators( - &client, - &format!("{}/validators", base_url), - block_height + 1, - ) - .await?; - let next_validators = Set::new(next_validator_response, None); +use tendermint_light_client_verifier::types::LightBlock; - sort_signatures_by_validators_power_desc(&mut signed_header, &validators); - Ok(LightBlock::new( - signed_header, - validators, - next_validators, - Id::new(peer_id), - )) +pub fn load_light_block(block_height: u64) -> Result> { + let mut file = File::open(&format!("files/block_{}.json", block_height))?; + let mut block_response_raw = String::new(); + file.read_to_string(&mut block_response_raw) + .expect(&format!("Failed to read block number {}", block_height)); + Ok(serde_json::from_str(&block_response_raw)?) } diff --git a/helper/src/lib.rs b/helper/src/lib.rs deleted file mode 100644 index 523c81509d..0000000000 --- a/helper/src/lib.rs +++ /dev/null @@ -1,145 +0,0 @@ -use cargo_metadata::Metadata; -use chrono::Local; -pub use sp1_build::BuildArgs; -use std::{path::Path, process::ExitStatus}; - -fn current_datetime() -> String { - let now = Local::now(); - now.format("%Y-%m-%d %H:%M:%S").to_string() -} - -/// Re-run the cargo command if the Cargo.toml or Cargo.lock file changes. -fn cargo_rerun_if_changed(metadata: &Metadata, program_dir: &Path) { - // Tell cargo to rerun the script only if program/{src, bin, build.rs, Cargo.toml} changes - // Ref: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rerun-if-changed - let dirs = vec![ - program_dir.join("src"), - program_dir.join("bin"), - program_dir.join("build.rs"), - program_dir.join("Cargo.toml"), - ]; - for dir in dirs { - if dir.exists() { - println!( - "cargo::rerun-if-changed={}", - dir.canonicalize().unwrap().display() - ); - } - } - - // Re-run the build script if the workspace root's Cargo.lock changes. If the program is its own - // workspace, this will be the program's Cargo.lock. - println!( - "cargo:rerun-if-changed={}", - metadata.workspace_root.join("Cargo.lock").as_str() - ); - - // Re-run if any local dependency changes. - for package in &metadata.packages { - for dependency in &package.dependencies { - if let Some(path) = &dependency.path { - println!("cargo:rerun-if-changed={}", path.as_str()); - } - } - } -} - -/// Executes the `cargo prove build` command in the program directory. If there are any cargo prove -/// build arguments, they are added to the command. -fn execute_build_cmd( - program_dir: &impl AsRef, - args: Option, -) -> Result { - // Check if RUSTC_WORKSPACE_WRAPPER is set to clippy-driver (i.e. if `cargo clippy` is the current - // compiler). If so, don't execute `cargo prove build` because it breaks rust-analyzer's `cargo clippy` feature. - let is_clippy_driver = std::env::var("RUSTC_WORKSPACE_WRAPPER") - .map(|val| val.contains("clippy-driver")) - .unwrap_or(false); - if is_clippy_driver { - println!("cargo:warning=Skipping build due to clippy invocation."); - return Ok(std::process::ExitStatus::default()); - } - - // Build the program with the given arguments. - let path_output = if let Some(args) = args { - sp1_build::build_program(&args, Some(program_dir.as_ref().to_path_buf())) - } else { - sp1_build::build_program( - &BuildArgs::default(), - Some(program_dir.as_ref().to_path_buf()), - ) - }; - if let Err(err) = path_output { - panic!("Failed to build SP1 program: {}.", err); - } - - Ok(ExitStatus::default()) -} - -/// Builds the program if the program at the specified path, or one of its dependencies, changes. -/// -/// This function monitors the program and its dependencies for changes. If any changes are detected, -/// it triggers a rebuild of the program. -/// -/// # Arguments -/// -/// * `path` - A string slice that holds the path to the program directory. -/// -/// This function is useful for automatically rebuilding the program during development -/// when changes are made to the source code or its dependencies. -/// -/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program. -pub fn build_program(path: &str) { - build_program_internal(path, None) -} - -/// Builds the program with the given arguments if the program at path, or one of its dependencies, -/// changes. -/// -/// # Arguments -/// -/// * `path` - A string slice that holds the path to the program directory. -/// * `args` - A [`BuildArgs`] struct that contains various build configuration options. -/// -/// Set the `SP1_SKIP_PROGRAM_BUILD` environment variable to `true` to skip building the program. -pub fn build_program_with_args(path: &str, args: BuildArgs) { - build_program_internal(path, Some(args)) -} - -/// Internal helper function to build the program with or without arguments. -fn build_program_internal(path: &str, args: Option) { - // Get the root package name and metadata. - let program_dir = std::path::Path::new(path); - let metadata_file = program_dir.join("Cargo.toml"); - let mut metadata_cmd = cargo_metadata::MetadataCommand::new(); - let metadata = metadata_cmd.manifest_path(metadata_file).exec().unwrap(); - let root_package = metadata.root_package(); - let root_package_name = root_package - .as_ref() - .map(|p| p.name.as_str()) - .unwrap_or("Program"); - - // Skip the program build if the SP1_SKIP_PROGRAM_BUILD environment variable is set to true. - let skip_program_build = std::env::var("SP1_SKIP_PROGRAM_BUILD") - .map(|v| v.eq_ignore_ascii_case("true")) - .unwrap_or(false); - if skip_program_build { - println!( - "cargo:warning=Build skipped for {} at {} due to SP1_SKIP_PROGRAM_BUILD flag", - root_package_name, - current_datetime() - ); - return; - } - - // Activate the build command if the dependencies change. - cargo_rerun_if_changed(&metadata, program_dir); - - let _ = execute_build_cmd(&program_dir, args); - - println!( - "cargo:warning={} built at {}", - root_package_name, - current_datetime() - ); -} diff --git a/recursion/compiler/src/ir/fold.rs b/recursion/compiler/src/ir/fold.rs deleted file mode 100644 index 57e132f640..0000000000 --- a/recursion/compiler/src/ir/fold.rs +++ /dev/null @@ -1,21 +0,0 @@ -use sp1_recursion_derive::DslVariable; - -use super::{Ext, Felt, Var}; -use crate::ir::Builder; -use crate::ir::MemIndex; -use crate::ir::MemVariable; -use crate::ir::Ptr; -use crate::ir::Variable; -use crate::ir::{Array, Config}; - -#[derive(DslVariable, Debug, Clone)] -pub struct FriFoldInput { - pub z: Ext, - pub alpha: Ext, - pub x: Felt, - pub log_height: Var, - pub mat_opening: Array>, - pub ps_at_z: Array>, - pub alpha_pow: Array>, - pub ro: Array>, -} diff --git a/recursion/gnark-cli/src/main.rs b/recursion/gnark-cli/src/main.rs deleted file mode 100644 index 61f5e0602a..0000000000 --- a/recursion/gnark-cli/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! A simple CLI that wraps the gnark-ffi crate. This is called using Docker in gnark-ffi when the -//! native feature is disabled. - -use sp1_recursion_gnark_ffi::ffi::{ - build_plonk_bn254, prove_plonk_bn254, test_plonk_bn254, verify_plonk_bn254, -}; - -use clap::{Args, Parser, Subcommand}; -use std::{ - fs::File, - io::{read_to_string, Write}, -}; - -#[derive(Debug, Parser)] -struct Cli { - #[command(subcommand)] - command: Command, -} - -#[allow(clippy::enum_variant_names)] -#[derive(Debug, Subcommand)] -enum Command { - BuildPlonk(BuildArgs), - ProvePlonk(ProveArgs), - VerifyPlonk(VerifyArgs), - TestPlonk(TestArgs), -} - -#[derive(Debug, Args)] -struct BuildArgs { - data_dir: String, -} - -#[derive(Debug, Args)] -struct ProveArgs { - data_dir: String, - witness_path: String, - output_path: String, -} - -#[derive(Debug, Args)] -struct VerifyArgs { - data_dir: String, - proof_path: String, - vkey_hash: String, - committed_values_digest: String, - output_path: String, -} - -#[derive(Debug, Args)] -struct TestArgs { - witness_json: String, - constraints_json: String, -} - -fn run_build(args: BuildArgs) { - build_plonk_bn254(&args.data_dir); -} - -fn run_prove(args: ProveArgs) { - let proof = prove_plonk_bn254(&args.data_dir, &args.witness_path); - let mut file = File::create(&args.output_path).unwrap(); - bincode::serialize_into(&mut file, &proof).unwrap(); -} - -fn run_verify(args: VerifyArgs) { - // For proof, we read the string from file since it can be large. - let file = File::open(&args.proof_path).unwrap(); - let proof = read_to_string(file).unwrap(); - let result = verify_plonk_bn254( - &args.data_dir, - proof.trim(), - &args.vkey_hash, - &args.committed_values_digest, - ); - let output = match result { - Ok(_) => "OK".to_string(), - Err(e) => e, - }; - let mut file = File::create(&args.output_path).unwrap(); - file.write_all(output.as_bytes()).unwrap(); -} - -fn run_test(args: TestArgs) { - test_plonk_bn254(&args.witness_json, &args.constraints_json); -} - -fn main() { - let cli = Cli::parse(); - - match cli.command { - Command::BuildPlonk(args) => run_build(args), - Command::ProvePlonk(args) => run_prove(args), - Command::VerifyPlonk(args) => run_verify(args), - Command::TestPlonk(args) => run_test(args), - } -} diff --git a/recursion/gnark-ffi/go/sp1/prove.go b/recursion/gnark-ffi/go/sp1/prove.go deleted file mode 100644 index 7260f99ff7..0000000000 --- a/recursion/gnark-ffi/go/sp1/prove.go +++ /dev/null @@ -1,85 +0,0 @@ -package sp1 - -import ( - "bufio" - "encoding/json" - "os" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/plonk" - "github.com/consensys/gnark/frontend" -) - -func Prove(dataDir string, witnessPath string) Proof { - // Sanity check the required arguments have been provided. - if dataDir == "" { - panic("dataDirStr is required") - } - os.Setenv("CONSTRAINTS_JSON", dataDir+"/"+constraintsJsonFile) - - // Read the R1CS. - scsFile, err := os.Open(dataDir + "/" + circuitPath) - if err != nil { - panic(err) - } - scs := plonk.NewCS(ecc.BN254) - scs.ReadFrom(scsFile) - defer scsFile.Close() - - // Read the proving key. - pkFile, err := os.Open(dataDir + "/" + pkPath) - if err != nil { - panic(err) - } - pk := plonk.NewProvingKey(ecc.BN254) - bufReader := bufio.NewReaderSize(pkFile, 1024*1024) - pk.UnsafeReadFrom(bufReader) - defer pkFile.Close() - - // Read the verifier key. - vkFile, err := os.Open(dataDir + "/" + vkPath) - if err != nil { - panic(err) - } - vk := plonk.NewVerifyingKey(ecc.BN254) - vk.ReadFrom(vkFile) - defer vkFile.Close() - - // Read the file. - data, err := os.ReadFile(witnessPath) - if err != nil { - panic(err) - } - - // Deserialize the JSON data into a slice of Instruction structs - var witnessInput WitnessInput - err = json.Unmarshal(data, &witnessInput) - if err != nil { - panic(err) - } - - // Generate the witness. - assignment := NewCircuit(witnessInput) - witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) - if err != nil { - panic(err) - } - publicWitness, err := witness.Public() - if err != nil { - panic(err) - } - - // Generate the proof. - proof, err := plonk.Prove(scs, pk, witness) - if err != nil { - panic(err) - } - - // Verify proof. - err = plonk.Verify(proof, vk, publicWitness) - if err != nil { - panic(err) - } - - return NewSP1PlonkBn254Proof(&proof, witnessInput) -} diff --git a/recursion/gnark-ffi/go/sp1/verify.go b/recursion/gnark-ffi/go/sp1/verify.go deleted file mode 100644 index 27c459c991..0000000000 --- a/recursion/gnark-ffi/go/sp1/verify.go +++ /dev/null @@ -1,58 +0,0 @@ -package sp1 - -import ( - "bytes" - "encoding/hex" - "os" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend/plonk" - "github.com/consensys/gnark/frontend" - "github.com/succinctlabs/sp1-recursion-gnark/sp1/babybear" -) - -func Verify(verifyCmdDataDir string, verifyCmdProof string, verifyCmdVkeyHash string, verifyCmdCommitedValuesDigest string) error { - // Sanity check the required arguments have been provided. - if verifyCmdDataDir == "" { - panic("--data is required") - } - - // Decode the proof. - proofDecodedBytes, err := hex.DecodeString(verifyCmdProof) - if err != nil { - panic(err) - } - proof := plonk.NewProof(ecc.BN254) - if _, err := proof.ReadFrom(bytes.NewReader(proofDecodedBytes)); err != nil { - panic(err) - } - - // Read the verifier key. - vkFile, err := os.Open(verifyCmdDataDir + "/" + vkPath) - if err != nil { - panic(err) - } - vk := plonk.NewVerifyingKey(ecc.BN254) - vk.ReadFrom(vkFile) - - // Compute the public witness. - circuit := Circuit{ - Vars: []frontend.Variable{}, - Felts: []babybear.Variable{}, - Exts: []babybear.ExtensionVariable{}, - VkeyHash: verifyCmdVkeyHash, - CommitedValuesDigest: verifyCmdCommitedValuesDigest, - } - witness, err := frontend.NewWitness(&circuit, ecc.BN254.ScalarField()) - if err != nil { - panic(err) - } - publicWitness, err := witness.Public() - if err != nil { - panic(err) - } - - // Verify proof. - err = plonk.Verify(proof, vk, publicWitness) - return err -} diff --git a/recursion/gnark-ffi/src/ffi/docker.rs b/recursion/gnark-ffi/src/ffi/docker.rs deleted file mode 100644 index 46b21c8423..0000000000 --- a/recursion/gnark-ffi/src/ffi/docker.rs +++ /dev/null @@ -1,114 +0,0 @@ -use sp1_core::SP1_CIRCUIT_VERSION; - -use crate::PlonkBn254Proof; -use std::io::Write; -use std::process::Command; - -/// Checks that docker is installed and running. -fn check_docker() -> bool { - let output = Command::new("docker").arg("info").output(); - output.is_ok() && output.unwrap().status.success() -} - -/// Panics if docker is not installed and running. -fn assert_docker() { - if !check_docker() { - panic!("Failed to run `docker info`. Please ensure that docker is installed and running."); - } -} - -fn get_docker_image() -> String { - std::env::var("SP1_GNARK_IMAGE") - .unwrap_or_else(|_| format!("ghcr.io/succinctlabs/sp1-gnark:{}", SP1_CIRCUIT_VERSION)) -} - -/// Calls `docker run` with the given arguments and bind mounts. -fn call_docker(args: &[&str], mounts: &[(&str, &str)]) -> anyhow::Result<()> { - log::info!("Running {} in docker", args[0]); - let mut cmd = Command::new("docker"); - cmd.args(["run", "--rm"]); - for (src, dest) in mounts { - cmd.arg("-v").arg(format!("{}:{}", src, dest)); - } - cmd.arg(get_docker_image()); - cmd.args(args); - if !cmd.status()?.success() { - log::error!("Failed to run `docker run`: {:?}", cmd); - return Err(anyhow::anyhow!("docker command failed")); - } - Ok(()) -} - -pub fn prove_plonk_bn254(data_dir: &str, witness_path: &str) -> PlonkBn254Proof { - let output_file = tempfile::NamedTempFile::new().unwrap(); - let mounts = [ - (data_dir, "/circuit"), - (witness_path, "/witness"), - (output_file.path().to_str().unwrap(), "/output"), - ]; - assert_docker(); - call_docker(&["prove-plonk", "/circuit", "/witness", "/output"], &mounts) - .expect("failed to prove with docker"); - bincode::deserialize_from(&output_file).expect("failed to deserialize result") -} - -pub fn build_plonk_bn254(data_dir: &str) { - let circuit_dir = if data_dir.ends_with("dev") { - "/circuit_dev" - } else { - "/circuit" - }; - let mounts = [(data_dir, circuit_dir)]; - assert_docker(); - call_docker(&["build-plonk", circuit_dir], &mounts).expect("failed to build with docker"); -} - -pub fn verify_plonk_bn254( - data_dir: &str, - proof: &str, - vkey_hash: &str, - committed_values_digest: &str, -) -> Result<(), String> { - // Write proof string to a file since it can be large. - let mut proof_file = tempfile::NamedTempFile::new().unwrap(); - proof_file.write_all(proof.as_bytes()).unwrap(); - let output_file = tempfile::NamedTempFile::new().unwrap(); - let mounts = [ - (data_dir, "/circuit"), - (proof_file.path().to_str().unwrap(), "/proof"), - (output_file.path().to_str().unwrap(), "/output"), - ]; - assert_docker(); - call_docker( - &[ - "verify-plonk", - "/circuit", - "/proof", - vkey_hash, - committed_values_digest, - "/output", - ], - &mounts, - ) - .expect("failed to verify with docker"); - let result = std::fs::read_to_string(output_file.path()).unwrap(); - if result == "OK" { - Ok(()) - } else { - Err(result) - } -} - -pub fn test_plonk_bn254(witness_json: &str, constraints_json: &str) { - let mounts = [ - (constraints_json, "/constraints"), - (witness_json, "/witness"), - ]; - assert_docker(); - call_docker(&["test-plonk", "/constraints", "/witness"], &mounts) - .expect("failed to test with docker"); -} - -pub fn test_babybear_poseidon2() { - unimplemented!() -} diff --git a/recursion/gnark-ffi/src/ffi/native.rs b/recursion/gnark-ffi/src/ffi/native.rs deleted file mode 100644 index 9d88a6b5b6..0000000000 --- a/recursion/gnark-ffi/src/ffi/native.rs +++ /dev/null @@ -1,144 +0,0 @@ -#![allow(unused)] - -//! FFI bindings for the Go code. The functions exported in this module are safe to call from Rust. -//! All C strings and other C memory should be freed in Rust, including C Strings returned by Go. -//! Although we cast to *mut c_char because the Go signatures can't be immutable, the Go functions -//! should not modify the strings. - -use crate::PlonkBn254Proof; -use cfg_if::cfg_if; -use sp1_core::SP1_CIRCUIT_VERSION; -use std::ffi::{c_char, CString}; - -#[allow(warnings, clippy::all)] -mod bind { - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -} -use bind::*; - -pub fn prove_plonk_bn254(data_dir: &str, witness_path: &str) -> PlonkBn254Proof { - let data_dir = CString::new(data_dir).expect("CString::new failed"); - let witness_path = CString::new(witness_path).expect("CString::new failed"); - - let proof = unsafe { - let proof = bind::ProvePlonkBn254( - data_dir.as_ptr() as *mut c_char, - witness_path.as_ptr() as *mut c_char, - ); - // Safety: The pointer is returned from the go code and is guaranteed to be valid. - *proof - }; - - proof.into_rust() -} - -pub fn build_plonk_bn254(data_dir: &str) { - let data_dir = CString::new(data_dir).expect("CString::new failed"); - - unsafe { - bind::BuildPlonkBn254(data_dir.as_ptr() as *mut c_char); - } -} - -pub fn verify_plonk_bn254( - data_dir: &str, - proof: &str, - vkey_hash: &str, - committed_values_digest: &str, -) -> Result<(), String> { - let data_dir = CString::new(data_dir).expect("CString::new failed"); - let proof = CString::new(proof).expect("CString::new failed"); - let vkey_hash = CString::new(vkey_hash).expect("CString::new failed"); - let committed_values_digest = - CString::new(committed_values_digest).expect("CString::new failed"); - - let err_ptr = unsafe { - bind::VerifyPlonkBn254( - data_dir.as_ptr() as *mut c_char, - proof.as_ptr() as *mut c_char, - vkey_hash.as_ptr() as *mut c_char, - committed_values_digest.as_ptr() as *mut c_char, - ) - }; - if err_ptr.is_null() { - Ok(()) - } else { - // Safety: The error message is returned from the go code and is guaranteed to be valid. - let err = unsafe { CString::from_raw(err_ptr) }; - Err(err.into_string().unwrap()) - } -} - -pub fn test_plonk_bn254(witness_json: &str, constraints_json: &str) { - unsafe { - let witness_json = CString::new(witness_json).expect("CString::new failed"); - let build_dir = CString::new(constraints_json).expect("CString::new failed"); - let err_ptr = bind::TestPlonkBn254( - witness_json.as_ptr() as *mut c_char, - build_dir.as_ptr() as *mut c_char, - ); - if !err_ptr.is_null() { - // Safety: The error message is returned from the go code and is guaranteed to be valid. - let err = CString::from_raw(err_ptr); - panic!("TestPlonkBn254 failed: {}", err.into_string().unwrap()); - } - } -} - -pub fn test_babybear_poseidon2() { - unsafe { - let err_ptr = bind::TestPoseidonBabyBear2(); - if !err_ptr.is_null() { - // Safety: The error message is returned from the go code and is guaranteed to be valid. - let err = CString::from_raw(err_ptr); - panic!("TestPlonkBn254 failed: {}", err.into_string().unwrap()); - } - } -} - -/// Converts a C string into a Rust String. -/// -/// # Safety -/// This function frees the string memory, so the caller must ensure that the pointer is not used -/// after this function is called. -unsafe fn c_char_ptr_to_string(input: *mut c_char) -> String { - unsafe { - CString::from_raw(input) // Converts a pointer that C uses into a CString - .into_string() - .expect("CString::into_string failed") - } -} - -impl C_PlonkBn254Proof { - /// Converts a C PlonkBn254Proof into a Rust PlonkBn254Proof, freeing the C strings. - fn into_rust(self) -> PlonkBn254Proof { - // Safety: The raw pointers are not used anymore after converted into Rust strings. - unsafe { - PlonkBn254Proof { - public_inputs: [ - c_char_ptr_to_string(self.PublicInputs[0]), - c_char_ptr_to_string(self.PublicInputs[1]), - ], - encoded_proof: c_char_ptr_to_string(self.EncodedProof), - raw_proof: c_char_ptr_to_string(self.RawProof), - plonk_vkey_hash: [0; 32], - } - } - } -} - -#[cfg(test)] -mod tests { - use p3_baby_bear::BabyBear; - use p3_field::AbstractField; - use p3_symmetric::Permutation; - - #[test] - pub fn test_babybear_poseidon2() { - let perm = sp1_core::utils::inner_perm(); - let zeros = [BabyBear::zero(); 16]; - let result = perm.permute(zeros); - println!("{:?}", result); - super::test_babybear_poseidon2(); - } -} diff --git a/release-plz.toml b/release-plz.toml index ced25f8913..6f51b01bec 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -3,3 +3,5 @@ git_release_enable = false # Disable git tags for all packages by default git_tag_enable = false +# Don't verify package build +publish_no_verify = true diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000..66b2930ca9 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,11 @@ +reorder_imports = true +imports_granularity = "Crate" +use_small_heuristics = "Max" +comment_width = 100 +wrap_comments = true +binop_separator = "Back" +trailing_comma = "Vertical" +trailing_semicolon = false +use_field_init_shorthand = true +format_code_in_doc_comments = true +doc_comment_code_block_width = 100 \ No newline at end of file diff --git a/sdk/build.rs b/sdk/build.rs deleted file mode 100644 index 594550b4a7..0000000000 --- a/sdk/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - vergen::EmitBuilder::builder() - .build_timestamp() - .git_sha(true) - .emit() - .unwrap(); -} diff --git a/sdk/src/install.rs b/sdk/src/install.rs deleted file mode 100644 index 8c6e250560..0000000000 --- a/sdk/src/install.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::{cmp::min, io::Write, path::PathBuf, process::Command}; - -use futures::{Future, StreamExt}; -use indicatif::{ProgressBar, ProgressStyle}; -use reqwest::Client; -use tokio::{runtime, task::block_in_place}; - -use crate::SP1_CIRCUIT_VERSION; - -/// The base URL for the S3 bucket containing the plonk bn254 artifacts. -pub const PLONK_BN254_ARTIFACTS_URL_BASE: &str = "https://sp1-circuits.s3-us-east-2.amazonaws.com"; - -/// Gets the directory where the PLONK artifacts are installed. -fn plonk_bn254_artifacts_dir() -> PathBuf { - dirs::home_dir() - .unwrap() - .join(".sp1") - .join("circuits") - .join("plonk_bn254") - .join(SP1_CIRCUIT_VERSION) -} - -/// Tries to install the PLONK artifacts if they are not already installed. -pub fn try_install_plonk_bn254_artifacts() -> PathBuf { - let build_dir = plonk_bn254_artifacts_dir(); - - if build_dir.exists() { - println!( - "[sp1] plonk bn254 artifacts already seem to exist at {}. if you want to re-download them, delete the directory", - build_dir.display() - ); - } else { - println!( - "[sp1] plonk bn254 artifacts for version {} do not exist at {}. downloading...", - SP1_CIRCUIT_VERSION, - build_dir.display() - ); - install_plonk_bn254_artifacts(build_dir.clone()); - } - build_dir -} - -/// Install the latest plonk bn254 artifacts. -/// -/// This function will download the latest plonk bn254 artifacts from the S3 bucket and extract them to -/// the directory specified by [plonk_bn254_artifacts_dir()]. -pub fn install_plonk_bn254_artifacts(build_dir: PathBuf) { - // Create the build directory. - std::fs::create_dir_all(&build_dir).expect("failed to create build directory"); - - // Download the artifacts. - let download_url = format!( - "{}/{}.tar.gz", - PLONK_BN254_ARTIFACTS_URL_BASE, SP1_CIRCUIT_VERSION - ); - let mut artifacts_tar_gz_file = - tempfile::NamedTempFile::new().expect("failed to create tempfile"); - let client = Client::builder() - .build() - .expect("failed to create reqwest client"); - block_on(download_file( - &client, - &download_url, - &mut artifacts_tar_gz_file, - )) - .expect("failed to download file"); - - // Extract the tarball to the build directory. - let mut res = Command::new("tar") - .args([ - "-Pxzf", - artifacts_tar_gz_file.path().to_str().unwrap(), - "-C", - build_dir.to_str().unwrap(), - ]) - .spawn() - .expect("failed to extract tarball"); - res.wait().unwrap(); - - println!( - "[sp1] downloaded {} to {:?}", - download_url, - build_dir.to_str().unwrap(), - ); -} - -/// The directory where the plonk bn254 artifacts will be stored based on [PLONK_BN254_ARTIFACTS_VERSION] -/// and [PLONK_BN254_ARTIFACTS_URL_BASE]. -pub fn install_plonk_bn254_artifacts_dir() -> PathBuf { - dirs::home_dir() - .unwrap() - .join(".sp1") - .join("circuits") - .join(SP1_CIRCUIT_VERSION) -} - -/// Download the file with a progress bar that indicates the progress. -pub async fn download_file( - client: &Client, - url: &str, - file: &mut tempfile::NamedTempFile, -) -> std::result::Result<(), String> { - let res = client - .get(url) - .send() - .await - .or(Err(format!("Failed to GET from '{}'", &url)))?; - - let total_size = res - .content_length() - .ok_or(format!("Failed to get content length from '{}'", &url))?; - - let pb = ProgressBar::new(total_size); - pb.set_style(ProgressStyle::default_bar() - .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap() - .progress_chars("#>-")); - - let mut downloaded: u64 = 0; - let mut stream = res.bytes_stream(); - while let Some(item) = stream.next().await { - let chunk = item.or(Err("Error while downloading file"))?; - file.write_all(&chunk) - .or(Err("Error while writing to file"))?; - let new = min(downloaded + (chunk.len() as u64), total_size); - downloaded = new; - pb.set_position(new); - } - pb.finish(); - - Ok(()) -} - -/// Utility method for blocking on an async function. If we're already in a tokio runtime, we'll -/// block in place. Otherwise, we'll create a new runtime. -pub fn block_on(fut: impl Future) -> T { - // Handle case if we're already in an tokio runtime. - if let Ok(handle) = runtime::Handle::try_current() { - block_in_place(|| handle.block_on(fut)) - } else { - // Otherwise create a new runtime. - let rt = runtime::Runtime::new().expect("Failed to create a new runtime"); - rt.block_on(fut) - } -} diff --git a/server/proto/api.proto b/server/proto/api.proto deleted file mode 100644 index 220818beb4..0000000000 --- a/server/proto/api.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; - -package api; - -service ProverService { - rpc ProveCore(ProveCoreRequest) returns (ProveCoreResponse) {} - rpc Compress(CompressRequest) returns (CompressResponse) {} -} - -message ProveCoreRequest { - bytes data = 1; -} - -message ProveCoreResponse { - bytes result = 1; -} - -message CompressRequest { - bytes data = 1; -} - -message CompressResponse { - bytes result = 1; -} \ No newline at end of file diff --git a/server/src/lib.rs b/server/src/lib.rs deleted file mode 100644 index 33c653a003..0000000000 --- a/server/src/lib.rs +++ /dev/null @@ -1,277 +0,0 @@ -#[rustfmt::skip] -pub mod proto { - pub mod api; -} - -use core::time::Duration; -use std::process::Command; -use std::process::Stdio; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use crate::proto::api::ProverServiceClient; - -use serde::{Deserialize, Serialize}; -use sp1_core::io::SP1Stdin; -use sp1_core::stark::ShardProof; -use sp1_core::utils::SP1CoreProverError; -use sp1_prover::types::SP1ProvingKey; -use sp1_prover::InnerSC; -use sp1_prover::SP1CoreProof; -use sp1_prover::SP1RecursionProverError; -use sp1_prover::SP1ReduceProof; -use sp1_prover::SP1VerifyingKey; -use tokio::runtime::Runtime; -use twirp::url::Url; -use twirp::Client; - -/// A remote client to [sp1_prover::SP1Prover] that runs inside a container. -/// -/// This is currently used to provide experimental support for GPU hardware acceleration. -/// -/// **WARNING**: This is an experimental feature and may not work as expected. -pub struct SP1ProverServer { - /// The gRPC client to communicate with the container. - client: Client, - /// The name of the container. - container_name: String, - /// A flag to indicate whether the container has already been cleaned up. - cleaned_up: Arc, -} - -/// The payload for the [sp1_prover::SP1Prover::prove_core] method. -/// -/// We use this object to serialize and deserialize the payload from the client to the server. -#[derive(Serialize, Deserialize)] -pub struct ProveCoreRequestPayload { - /// The proving key. - pub pk: SP1ProvingKey, - /// The input stream. - pub stdin: SP1Stdin, -} - -/// The payload for the [sp1_prover::SP1Prover::compress] method. -/// -/// We use this object to serialize and deserialize the payload from the client to the server. -#[derive(Serialize, Deserialize)] -pub struct CompressRequestPayload { - /// The verifying key. - pub vk: SP1VerifyingKey, - /// The core proof. - pub proof: SP1CoreProof, - /// The deferred proofs. - pub deferred_proofs: Vec>, -} - -impl SP1ProverServer { - /// Creates a new [SP1Prover] that runs inside a Docker container and returns a - /// [SP1ProverClient] that can be used to communicate with the container. - pub fn new() -> Self { - let container_name = "sp1-gpu"; - let image_name = "jtguibas/sp1-gpu:v1.1.5"; - - let cleaned_up = Arc::new(AtomicBool::new(false)); - let cleanup_name = container_name; - let cleanup_flag = cleaned_up.clone(); - - // Spawn a new thread to start the Docker container. - std::thread::spawn(move || { - Command::new("sudo") - .args([ - "docker", - "run", - "-e", - "RUST_LOG=debug", - "-p", - "3000:3000", - "--rm", - "--runtime=nvidia", - "--gpus", - "all", - "--name", - container_name, - image_name, - ]) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .status() - .expect("failed to start Docker container"); - }); - - ctrlc::set_handler(move || { - tracing::debug!("received Ctrl+C, cleaning up..."); - if !cleanup_flag.load(Ordering::SeqCst) { - cleanup_container(cleanup_name); - cleanup_flag.store(true, Ordering::SeqCst); - } - std::process::exit(0); - }) - .unwrap(); - - tracing::debug!("sleeping for 20 seconds to allow server to start"); - std::thread::sleep(Duration::from_secs(20)); - - SP1ProverServer { - client: Client::from_base_url( - Url::parse("http://localhost:3000/twirp/").expect("failed to parse url"), - ) - .expect("failed to create client"), - container_name: container_name.to_string(), - cleaned_up: cleaned_up.clone(), - } - } - - /// Executes the [sp1_prover::SP1Prover::prove_core] method inside the container. - /// - /// TODO: We can probably create a trait to unify [sp1_prover::SP1Prover] and [SP1ProverClient]. - /// - /// **WARNING**: This is an experimental feature and may not work as expected. - pub fn prove_core( - &self, - pk: &SP1ProvingKey, - stdin: &SP1Stdin, - ) -> Result { - let payload = ProveCoreRequestPayload { - pk: pk.clone(), - stdin: stdin.clone(), - }; - let request = crate::proto::api::ProveCoreRequest { - data: bincode::serialize(&payload).unwrap(), - }; - let rt = Runtime::new().unwrap(); - let response = rt - .block_on(async { self.client.prove_core(request).await }) - .unwrap(); - let proof: SP1CoreProof = bincode::deserialize(&response.result).unwrap(); - Ok(proof) - } - - /// Executes the [sp1_prover::SP1Prover::compress] method inside the container. - /// - /// TODO: We can probably create a trait to unify [sp1_prover::SP1Prover] and [SP1ProverClient]. - /// - /// **WARNING**: This is an experimental feature and may not work as expected. - pub fn compress( - &self, - vk: &SP1VerifyingKey, - proof: SP1CoreProof, - deferred_proofs: Vec>, - ) -> Result, SP1RecursionProverError> { - let payload = CompressRequestPayload { - vk: vk.clone(), - proof, - deferred_proofs, - }; - let request = crate::proto::api::CompressRequest { - data: bincode::serialize(&payload).unwrap(), - }; - - let rt = Runtime::new().unwrap(); - let response = rt - .block_on(async { self.client.compress(request).await }) - .unwrap(); - let proof: SP1ReduceProof = bincode::deserialize(&response.result).unwrap(); - Ok(proof) - } -} - -impl Default for SP1ProverServer { - fn default() -> Self { - Self::new() - } -} - -impl Drop for SP1ProverServer { - fn drop(&mut self) { - if !self.cleaned_up.load(Ordering::SeqCst) { - tracing::debug!("dropping SP1ProverClient, cleaning up..."); - cleanup_container(&self.container_name); - self.cleaned_up.store(true, Ordering::SeqCst); - } - } -} - -/// Cleans up the a docker container with the given name. -fn cleanup_container(container_name: &str) { - tracing::debug!("cleaning up container: {}", container_name); - if let Err(e) = Command::new("sudo") - .args(["docker", "rm", "-f", container_name]) - .status() - { - eprintln!("failed to remove container: {}", e); - } -} - -#[cfg(test)] -mod tests { - use sp1_core::utils; - use sp1_core::utils::tests::FIBONACCI_ELF; - use sp1_prover::components::DefaultProverComponents; - use sp1_prover::{InnerSC, SP1CoreProof, SP1Prover, SP1ReduceProof}; - use twirp::url::Url; - use twirp::Client; - - use crate::SP1Stdin; - use crate::{proto::api::ProverServiceClient, ProveCoreRequestPayload}; - use crate::{CompressRequestPayload, SP1ProverServer}; - - #[ignore] - #[test] - fn test_client() { - utils::setup_logger(); - - let client = SP1ProverServer::new(); - - let prover = SP1Prover::::new(); - let (pk, vk) = prover.setup(FIBONACCI_ELF); - - println!("proving core"); - let proof = client.prove_core(&pk, &SP1Stdin::new()).unwrap(); - - println!("verifying core"); - prover.verify(&proof.proof, &vk).unwrap(); - - println!("proving compress"); - let proof = client.compress(&vk, proof, vec![]).unwrap(); - - println!("verifying compress"); - prover.verify_compressed(&proof, &vk).unwrap(); - } - - #[ignore] - #[tokio::test] - async fn test_prove_core() { - let client = - Client::from_base_url(Url::parse("http://localhost:3000/twirp/").unwrap()).unwrap(); - - let prover = SP1Prover::::new(); - let (pk, vk) = prover.setup(FIBONACCI_ELF); - let payload = ProveCoreRequestPayload { - pk, - stdin: SP1Stdin::new(), - }; - let request = crate::proto::api::ProveCoreRequest { - data: bincode::serialize(&payload).unwrap(), - }; - let proof = client.prove_core(request).await.unwrap(); - let proof: SP1CoreProof = bincode::deserialize(&proof.result).unwrap(); - prover.verify(&proof.proof, &vk).unwrap(); - - tracing::info!("compress"); - let payload = CompressRequestPayload { - vk: vk.clone(), - proof, - deferred_proofs: vec![], - }; - let request = crate::proto::api::CompressRequest { - data: bincode::serialize(&payload).unwrap(), - }; - let compressed_proof = client.compress(request).await.unwrap(); - let compressed_proof: SP1ReduceProof = - bincode::deserialize(&compressed_proof.result).unwrap(); - - tracing::info!("verify compressed"); - prover.verify_compressed(&compressed_proof, &vk).unwrap(); - } -} diff --git a/server/src/proto/api.rs b/server/src/proto/api.rs deleted file mode 100644 index 28390e38e0..0000000000 --- a/server/src/proto/api.rs +++ /dev/null @@ -1,91 +0,0 @@ -// This file is @generated by prost-build. -#[derive(serde::Serialize, serde::Deserialize)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProveCoreRequest { - #[prost(bytes = "vec", tag = "1")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProveCoreResponse { - #[prost(bytes = "vec", tag = "1")] - pub result: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompressRequest { - #[prost(bytes = "vec", tag = "1")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize)] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompressResponse { - #[prost(bytes = "vec", tag = "1")] - pub result: ::prost::alloc::vec::Vec, -} -pub use twirp; -pub const SERVICE_FQN: &str = "/api.ProverService"; -#[twirp::async_trait::async_trait] -pub trait ProverService { - async fn prove_core( - &self, - ctx: twirp::Context, - req: ProveCoreRequest, - ) -> Result; - async fn compress( - &self, - ctx: twirp::Context, - req: CompressRequest, - ) -> Result; -} -pub fn router(api: std::sync::Arc) -> twirp::Router -where - T: ProverService + Send + Sync + 'static, -{ - twirp::details::TwirpRouterBuilder::new(api) - .route( - "/ProveCore", - |api: std::sync::Arc, ctx: twirp::Context, req: ProveCoreRequest| async move { - api.prove_core(ctx, req).await - }, - ) - .route( - "/Compress", - |api: std::sync::Arc, ctx: twirp::Context, req: CompressRequest| async move { - api.compress(ctx, req).await - }, - ) - .build() -} -#[twirp::async_trait::async_trait] -pub trait ProverServiceClient: Send + Sync + std::fmt::Debug { - async fn prove_core( - &self, - req: ProveCoreRequest, - ) -> Result; - async fn compress( - &self, - req: CompressRequest, - ) -> Result; -} -#[twirp::async_trait::async_trait] -impl ProverServiceClient for twirp::client::Client { - async fn prove_core( - &self, - req: ProveCoreRequest, - ) -> Result { - let url = self.base_url.join("api.ProverService/ProveCore")?; - self.request(url, req).await - } - async fn compress( - &self, - req: CompressRequest, - ) -> Result { - let url = self.base_url.join("api.ProverService/Compress")?; - self.request(url, req).await - } -} diff --git a/sp1up/sp1up b/sp1up/sp1up index 1f139c75ad..c5038b59da 100755 --- a/sp1up/sp1up +++ b/sp1up/sp1up @@ -134,7 +134,11 @@ EOF done say "installing rust toolchain" - ensure "$bin_path" prove install-toolchain + if [ -n "$GITHUB_TOKEN" ]; then + ensure "$bin_path" prove install-toolchain --token "$GITHUB_TOKEN" + else + ensure "$bin_path" prove install-toolchain + fi say "installed rust toolchain" else # Install by cloning the repo with the provided branch/tag diff --git a/tests/bls12381-decompress/Cargo.toml b/tests/bls12381-decompress/Cargo.toml index 6fae053215..4cbe3547c7 100644 --- a/tests/bls12381-decompress/Cargo.toml +++ b/tests/bls12381-decompress/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -sp1-zkvm = { path = "../../zkvm/entrypoint", features = ["bls12381"] } +sp1-zkvm = { path = "../../zkvm/entrypoint" } diff --git a/tests/bls12381-fp/Cargo.lock b/tests/bls12381-fp/Cargo.lock new file mode 100644 index 0000000000..b73d80cb15 --- /dev/null +++ b/tests/bls12381-fp/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12381-fp-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bls12381-fp/Cargo.toml b/tests/bls12381-fp/Cargo.toml new file mode 100644 index 0000000000..e4f1b2965c --- /dev/null +++ b/tests/bls12381-fp/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bls12381-fp-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..0f499c13e9 Binary files /dev/null and b/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp/src/main.rs b/tests/bls12381-fp/src/main.rs new file mode 100644 index 0000000000..6a6a4c5b44 --- /dev/null +++ b/tests/bls12381-fp/src/main.rs @@ -0,0 +1,132 @@ +#![no_main] + +sp1_zkvm::entrypoint!(main); +use std::str::FromStr; + +use sp1_zkvm::lib::{ + syscall_bls12381_fp_addmod, syscall_bls12381_fp_mulmod, syscall_bls12381_fp_submod, +}; + +use num_bigint::BigUint; +use rand::Rng; + +fn add(lhs: &[u32; 12], rhs: &[u32; 12]) -> [u32; 12] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bls12381_fp_addmod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn sub(lhs: &[u32; 12], rhs: &[u32; 12]) -> [u32; 12] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bls12381_fp_submod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn mul(lhs: &[u32; 12], rhs: &[u32; 12]) -> [u32; 12] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bls12381_fp_mulmod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn random_u32_12() -> [u32; 12] { + let mut rng = rand::thread_rng(); + let mut arr = [0u32; 12]; + for i in 0..12 { + arr[i] = rng.gen(); + } + arr +} + +fn u32_12_to_biguint(arr: &[u32; 12]) -> BigUint { + let mut bytes = [0u8; 48]; + for i in 0..12 { + bytes[i * 4..(i + 1) * 4].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn reduce_modulo(arr: &[u32; 12], modulus: &BigUint) -> [u32; 12] { + let bigint = u32_12_to_biguint(arr); + let reduced = bigint % modulus; + let bytes = reduced.to_bytes_le(); + let mut result = [0u32; 12]; + for i in 0..12 { + if i * 4 < bytes.len() { + let mut slice = [0u8; 4]; + slice.copy_from_slice(&bytes[i * 4..(i * 4 + 4).min(bytes.len())]); + result[i] = u32::from_le_bytes(slice); + } + } + result +} + +pub fn main() { + let modulus = BigUint::from_str("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787").unwrap(); + let zero: [u32; 12] = [0; 12]; + let zero_bigint = BigUint::ZERO; + let one: [u32; 12] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let one_bigint = BigUint::from(1u32); + + for _ in 0..10 { + let a = random_u32_12(); + let b = random_u32_12(); + let a_reduced = reduce_modulo(&a, &modulus); + let b_reduced = reduce_modulo(&b, &modulus); + let a_bigint = u32_12_to_biguint(&a_reduced); + let b_bigint = u32_12_to_biguint(&b_reduced); + + // Test addition + assert_eq!( + (a_bigint.clone() + b_bigint.clone()) % &modulus, + u32_12_to_biguint(&add(&a_reduced, &b_reduced)) % &modulus + ); + + // Test addition with zero + assert_eq!( + (&a_bigint + &zero_bigint) % &modulus, + u32_12_to_biguint(&add(&a_reduced, &zero)) % &modulus + ); + + // Test subtraction + let expected_sub = if a_bigint < b_bigint { + ((a_bigint.clone() + &modulus) - b_bigint.clone()) % &modulus + } else { + (a_bigint.clone() - b_bigint.clone()) % &modulus + }; + assert_eq!( + expected_sub, + u32_12_to_biguint(&sub(&a_reduced, &b_reduced)) % &modulus + ); + + // Test subtraction with zero + assert_eq!( + (&a_bigint + &modulus - &zero_bigint) % &modulus, + u32_12_to_biguint(&sub(&a_reduced, &zero)) % &modulus + ); + + // Test multiplication + assert_eq!( + (a_bigint.clone() * b_bigint.clone()) % &modulus, + u32_12_to_biguint(&mul(&a_reduced, &b_reduced)) % &modulus + ); + + // Test multiplication with one + assert_eq!( + (&a_bigint * &one_bigint) % &modulus, + u32_12_to_biguint(&mul(&a_reduced, &one)) % &modulus + ); + + // Test multiplication with zero + assert_eq!( + (&a_bigint * &zero_bigint) % &modulus, + u32_12_to_biguint(&mul(&a_reduced, &zero)) % &modulus + ); + } + println!("All tests passed!"); +} diff --git a/tests/bls12381-fp2-addsub/Cargo.lock b/tests/bls12381-fp2-addsub/Cargo.lock new file mode 100644 index 0000000000..6bffb820fc --- /dev/null +++ b/tests/bls12381-fp2-addsub/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12381-fp2-addsub-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bls12381-fp2-addsub/Cargo.toml b/tests/bls12381-fp2-addsub/Cargo.toml new file mode 100644 index 0000000000..36ea097855 --- /dev/null +++ b/tests/bls12381-fp2-addsub/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bls12381-fp2-addsub-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..7602dd1d51 Binary files /dev/null and b/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp2-addsub/src/main.rs b/tests/bls12381-fp2-addsub/src/main.rs new file mode 100644 index 0000000000..efaaf9c53e --- /dev/null +++ b/tests/bls12381-fp2-addsub/src/main.rs @@ -0,0 +1,133 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use num_bigint::BigUint; +use rand::Rng; +use sp1_zkvm::syscalls::{syscall_bls12381_fp2_addmod, syscall_bls12381_fp2_submod}; +use std::{mem::transmute, str::FromStr}; + +const MODULUS: &str = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"; + +fn random_u64_6(modulus: &BigUint) -> [u64; 6] { + let mut rng = rand::thread_rng(); + let mut arr = [0u64; 6]; + let modulus_bytes = modulus.to_bytes_le(); + let modulus_u64: [u64; 6] = [ + u64::from_le_bytes(modulus_bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[24..32].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[32..40].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[40..48].try_into().unwrap()), + ]; + + for i in 0..6 { + arr[i] = rng.gen_range(0..modulus_u64[i]); + } + arr +} + +fn u64_6_to_biguint(arr: &[u64; 6]) -> BigUint { + let mut bytes = [0u8; 48]; + for i in 0..6 { + bytes[i * 8..(i + 1) * 8].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn fp2_add( + lhs_c0: &[u64; 6], + lhs_c1: &[u64; 6], + rhs_c0: &[u64; 6], + rhs_c1: &[u64; 6], +) -> ([u64; 6], [u64; 6]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(rhs.try_into().unwrap()) }; + + syscall_bls12381_fp2_addmod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + + let result_c0: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[0..12].try_into().unwrap()) }; + let result_c1: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[12..24].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +fn fp2_sub( + lhs_c0: &[u64; 6], + lhs_c1: &[u64; 6], + rhs_c0: &[u64; 6], + rhs_c1: &[u64; 6], +) -> ([u64; 6], [u64; 6]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(rhs.try_into().unwrap()) }; + + syscall_bls12381_fp2_submod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + + let result_c0: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[0..12].try_into().unwrap()) }; + let result_c1: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[12..24].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +pub fn main() { + let modulus = BigUint::from_str(MODULUS).unwrap(); + let zero = fp2_add(&[0; 6], &[0; 6], &[0; 6], &[0; 6]); + let zero_expected = ([0; 6], [0; 6]); + assert_eq!(zero, zero_expected); + + for _ in 0..10 { + let a_c0 = random_u64_6(&modulus); + let a_c1 = random_u64_6(&modulus); + let b_c0 = random_u64_6(&modulus); + let b_c1 = random_u64_6(&modulus); + + let a_c0_bigint = &u64_6_to_biguint(&a_c0); + let a_c1_bigint = &u64_6_to_biguint(&a_c1); + let b_c0_bigint = &u64_6_to_biguint(&b_c0); + let b_c1_bigint = &u64_6_to_biguint(&b_c1); + + let _a_c0: [u64; 6] = a_c0_bigint.to_u64_digits().try_into().unwrap(); + let _a_c1: [u64; 6] = a_c1_bigint.to_u64_digits().try_into().unwrap(); + let _b_c0: [u64; 6] = b_c0_bigint.to_u64_digits().try_into().unwrap(); + let _b_c1: [u64; 6] = b_c1_bigint.to_u64_digits().try_into().unwrap(); + + assert_eq!(a_c0, _a_c0); + assert_eq!(a_c1, _a_c1); + assert_eq!(b_c0, _b_c0); + assert_eq!(b_c1, _b_c1); + + // Fp2 Addition test + let c0 = (a_c0_bigint + b_c0_bigint) % &modulus; + let c1 = (a_c1_bigint + b_c1_bigint) % &modulus; + + let (res_c0, res_c1) = fp2_add(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_6_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_6_to_biguint(&res_c1) % &modulus); + + // Fp2 Subtraction test + let c0 = (a_c0_bigint + &modulus - b_c0_bigint) % &modulus; + let c1 = (a_c1_bigint + &modulus - b_c1_bigint) % &modulus; + + let (res_c0, res_c1) = fp2_sub(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_6_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_6_to_biguint(&res_c1) % &modulus); + } + + println!("All tests passed!"); +} diff --git a/tests/bls12381-fp2-mul/Cargo.lock b/tests/bls12381-fp2-mul/Cargo.lock new file mode 100644 index 0000000000..d99b6d20d5 --- /dev/null +++ b/tests/bls12381-fp2-mul/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12381-fp2-mul-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bls12381-fp2-mul/Cargo.toml b/tests/bls12381-fp2-mul/Cargo.toml new file mode 100644 index 0000000000..066cf20eb8 --- /dev/null +++ b/tests/bls12381-fp2-mul/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bls12381-fp2-mul-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..95247d98ad Binary files /dev/null and b/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp2-mul/src/main.rs b/tests/bls12381-fp2-mul/src/main.rs new file mode 100644 index 0000000000..ca4bd46daa --- /dev/null +++ b/tests/bls12381-fp2-mul/src/main.rs @@ -0,0 +1,96 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use num_bigint::BigUint; +use rand::Rng; +use sp1_zkvm::syscalls::syscall_bls12381_fp2_mulmod; +use std::{mem::transmute, str::FromStr}; + +const MODULUS: &str = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"; + +fn random_u64_6(modulus: &BigUint) -> [u64; 6] { + let mut rng = rand::thread_rng(); + let mut arr = [0u64; 6]; + let modulus_bytes = modulus.to_bytes_le(); + let modulus_u64: [u64; 6] = [ + u64::from_le_bytes(modulus_bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[24..32].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[32..40].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[40..48].try_into().unwrap()), + ]; + + for i in 0..6 { + arr[i] = rng.gen_range(0..modulus_u64[i]); + } + arr +} + +fn u64_6_to_biguint(arr: &[u64; 6]) -> BigUint { + let mut bytes = [0u8; 48]; + for i in 0..6 { + bytes[i * 8..(i + 1) * 8].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn fp2_mul( + lhs_c0: &[u64; 6], + lhs_c1: &[u64; 6], + rhs_c0: &[u64; 6], + rhs_c1: &[u64; 6], +) -> ([u64; 6], [u64; 6]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 24] = + unsafe { transmute::<[u64; 12], [u32; 24]>(rhs.try_into().unwrap()) }; + + syscall_bls12381_fp2_mulmod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + + let result_c0: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[0..12].try_into().unwrap()) }; + let result_c1: [u64; 6] = + unsafe { transmute::<[u32; 12], [u64; 6]>(lhs_transmuted[12..24].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +pub fn main() { + let modulus = BigUint::from_str(MODULUS).unwrap(); + + for _ in 0..10 { + let a_c0 = random_u64_6(&modulus); + let a_c1 = random_u64_6(&modulus); + let b_c0 = random_u64_6(&modulus); + let b_c1 = random_u64_6(&modulus); + + let a_c0_bigint = u64_6_to_biguint(&a_c0); + let a_c1_bigint = u64_6_to_biguint(&a_c1); + let b_c0_bigint = u64_6_to_biguint(&b_c0); + let b_c1_bigint = u64_6_to_biguint(&b_c1); + + let ac0_bc0_mod = (&a_c0_bigint * &b_c0_bigint) % &modulus; + let ac1_bc1_mod = (&a_c1_bigint * &b_c1_bigint) % &modulus; + + let c0 = if ac0_bc0_mod < ac1_bc1_mod { + (&modulus + ac0_bc0_mod - ac1_bc1_mod) % &modulus + } else { + (ac0_bc0_mod - ac1_bc1_mod) % &modulus + }; + + let c1 = ((&a_c0_bigint * &b_c1_bigint) % &modulus + + (&a_c1_bigint * &b_c0_bigint) % &modulus) + % &modulus; + + let (res_c0, res_c1) = fp2_mul(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_6_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_6_to_biguint(&res_c1) % &modulus); + } + + println!("All tests passed!"); +} diff --git a/tests/bls12381-mul/Cargo.toml b/tests/bls12381-mul/Cargo.toml index 41abc9f442..ae3dabb307 100644 --- a/tests/bls12381-mul/Cargo.toml +++ b/tests/bls12381-mul/Cargo.toml @@ -6,5 +6,5 @@ publish = false [dependencies] -sp1-zkvm = { path = "../../zkvm/entrypoint", features = ["bls12381"] } +sp1-zkvm = { path = "../../zkvm/entrypoint" } sp1-derive = { path = "../../derive" } diff --git a/tests/bn254-fp/Cargo.lock b/tests/bn254-fp/Cargo.lock new file mode 100644 index 0000000000..b018ea5f50 --- /dev/null +++ b/tests/bn254-fp/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bn254-fp-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bn254-fp/Cargo.toml b/tests/bn254-fp/Cargo.toml new file mode 100644 index 0000000000..993b04f3c0 --- /dev/null +++ b/tests/bn254-fp/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bn254-fp-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..b7d31090cb Binary files /dev/null and b/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp/src/main.rs b/tests/bn254-fp/src/main.rs new file mode 100644 index 0000000000..9bbdf90dcc --- /dev/null +++ b/tests/bn254-fp/src/main.rs @@ -0,0 +1,137 @@ +#![no_main] + +sp1_zkvm::entrypoint!(main); +use std::str::FromStr; + +use sp1_zkvm::lib::{syscall_bn254_fp_addmod, syscall_bn254_fp_mulmod, syscall_bn254_fp_submod}; + +use num_bigint::BigUint; +use rand::Rng; + +const NUM_LIMBS: usize = 8; + +fn add(lhs: &[u32; NUM_LIMBS], rhs: &[u32; NUM_LIMBS]) -> [u32; NUM_LIMBS] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bn254_fp_addmod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn sub(lhs: &[u32; NUM_LIMBS], rhs: &[u32; NUM_LIMBS]) -> [u32; NUM_LIMBS] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bn254_fp_submod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn mul(lhs: &[u32; NUM_LIMBS], rhs: &[u32; NUM_LIMBS]) -> [u32; NUM_LIMBS] { + unsafe { + let mut lhs_copy = *lhs; + syscall_bn254_fp_mulmod(lhs_copy.as_mut_ptr(), rhs.as_ptr()); + lhs_copy + } +} + +fn random_u32_8() -> [u32; NUM_LIMBS] { + let mut rng = rand::thread_rng(); + let mut arr = [0u32; NUM_LIMBS]; + for i in 0..NUM_LIMBS { + arr[i] = rng.gen(); + } + arr +} + +fn u32_8_to_biguint(arr: &[u32; NUM_LIMBS]) -> BigUint { + let mut bytes = [0u8; NUM_LIMBS * 4]; + for i in 0..NUM_LIMBS { + bytes[i * 4..(i + 1) * 4].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn reduce_modulo(arr: &[u32; NUM_LIMBS], modulus: &BigUint) -> [u32; NUM_LIMBS] { + let bigint = u32_8_to_biguint(arr); + let reduced = bigint % modulus; + let bytes = reduced.to_bytes_le(); + let mut result = [0u32; NUM_LIMBS]; + for i in 0..NUM_LIMBS { + let mut slice = [0u8; 4]; + if i * 4 < bytes.len() { + let end = (i * 4 + 4).min(bytes.len()); + let len = end - i * 4; + slice[..len].copy_from_slice(&bytes[i * 4..end]); + } + result[i] = u32::from_le_bytes(slice); + } + result +} + +pub fn main() { + let modulus = BigUint::from_str( + "21888242871839275222246405745257275088696311157297823662689037894645226208583", + ) + .unwrap(); + let zero: [u32; NUM_LIMBS] = [0; NUM_LIMBS]; + let zero_bigint = BigUint::ZERO; + let one: [u32; NUM_LIMBS] = [1, 0, 0, 0, 0, 0, 0, 0]; + let one_bigint = BigUint::from(1u32); + + for _ in 0..10 { + let a = random_u32_8(); + let b = random_u32_8(); + let a_reduced = reduce_modulo(&a, &modulus); + let b_reduced = reduce_modulo(&b, &modulus); + let a_bigint = u32_8_to_biguint(&a_reduced); + let b_bigint = u32_8_to_biguint(&b_reduced); + + // Test addition + assert_eq!( + (a_bigint.clone() + b_bigint.clone()) % &modulus, + u32_8_to_biguint(&add(&a_reduced, &b_reduced)) % &modulus + ); + + // Test addition with zero + assert_eq!( + (&a_bigint + &zero_bigint) % &modulus, + u32_8_to_biguint(&add(&a_reduced, &zero)) % &modulus + ); + + // Test subtraction + let expected_sub = if a_bigint < b_bigint { + ((a_bigint.clone() + &modulus) - b_bigint.clone()) % &modulus + } else { + (a_bigint.clone() - b_bigint.clone()) % &modulus + }; + assert_eq!( + expected_sub, + u32_8_to_biguint(&sub(&a_reduced, &b_reduced)) % &modulus + ); + + // Test subtraction with zero + assert_eq!( + (&a_bigint + &modulus - &zero_bigint) % &modulus, + u32_8_to_biguint(&sub(&a_reduced, &zero)) % &modulus + ); + + // Test multiplication + assert_eq!( + (a_bigint.clone() * b_bigint.clone()) % &modulus, + u32_8_to_biguint(&mul(&a_reduced, &b_reduced)) % &modulus + ); + + // Test multiplication with one + assert_eq!( + (&a_bigint * &one_bigint) % &modulus, + u32_8_to_biguint(&mul(&a_reduced, &one)) % &modulus + ); + + // Test multiplication with zero + assert_eq!( + (&a_bigint * &zero_bigint) % &modulus, + u32_8_to_biguint(&mul(&a_reduced, &zero)) % &modulus + ); + } + println!("All tests passed!"); +} diff --git a/tests/bn254-fp2-addsub/Cargo.lock b/tests/bn254-fp2-addsub/Cargo.lock new file mode 100644 index 0000000000..cbfc6f5e0b --- /dev/null +++ b/tests/bn254-fp2-addsub/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bn254-fp2-addsub-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bn254-fp2-addsub/Cargo.toml b/tests/bn254-fp2-addsub/Cargo.toml new file mode 100644 index 0000000000..7c065540a5 --- /dev/null +++ b/tests/bn254-fp2-addsub/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bn254-fp2-addsub-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..445a7aeed3 Binary files /dev/null and b/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp2-addsub/src/main.rs b/tests/bn254-fp2-addsub/src/main.rs new file mode 100644 index 0000000000..4ea802daa5 --- /dev/null +++ b/tests/bn254-fp2-addsub/src/main.rs @@ -0,0 +1,132 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use num_bigint::BigUint; +use rand::Rng; +use sp1_zkvm::syscalls::{syscall_bn254_fp2_addmod, syscall_bn254_fp2_submod}; +use std::{mem::transmute, str::FromStr}; + +const MODULUS: &str = + "21888242871839275222246405745257275088696311157297823662689037894645226208583"; + +fn random_u64_4(modulus: &BigUint) -> [u64; 4] { + let mut rng = rand::thread_rng(); + let mut arr = [0u64; 4]; + let modulus_bytes = modulus.to_bytes_le(); + let modulus_u64: [u64; 4] = [ + u64::from_le_bytes(modulus_bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[24..32].try_into().unwrap()), + ]; + + for i in 0..4 { + arr[i] = rng.gen_range(0..modulus_u64[i]); + } + arr +} + +fn u64_4_to_biguint(arr: &[u64; 4]) -> BigUint { + let mut bytes = [0u8; 32]; + for i in 0..4 { + bytes[i * 8..(i + 1) * 8].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn fp2_add( + lhs_c0: &[u64; 4], + lhs_c1: &[u64; 4], + rhs_c0: &[u64; 4], + rhs_c1: &[u64; 4], +) -> ([u64; 4], [u64; 4]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(rhs.try_into().unwrap()) }; + + syscall_bn254_fp2_addmod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + + let result_c0: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[0..8].try_into().unwrap()) }; + let result_c1: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[8..16].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +fn fp2_sub( + lhs_c0: &[u64; 4], + lhs_c1: &[u64; 4], + rhs_c0: &[u64; 4], + rhs_c1: &[u64; 4], +) -> ([u64; 4], [u64; 4]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(rhs.try_into().unwrap()) }; + + syscall_bn254_fp2_submod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + + let result_c0: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[0..8].try_into().unwrap()) }; + let result_c1: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[8..16].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +pub fn main() { + let modulus = BigUint::from_str(MODULUS).unwrap(); + let zero = fp2_add(&[0; 4], &[0; 4], &[0; 4], &[0; 4]); + let zero_expected = ([0; 4], [0; 4]); + assert_eq!(zero, zero_expected); + + for _ in 0..10 { + let a_c0 = random_u64_4(&modulus); + let a_c1 = random_u64_4(&modulus); + let b_c0 = random_u64_4(&modulus); + let b_c1 = random_u64_4(&modulus); + + let a_c0_bigint = &u64_4_to_biguint(&a_c0); + let a_c1_bigint = &u64_4_to_biguint(&a_c1); + let b_c0_bigint = &u64_4_to_biguint(&b_c0); + let b_c1_bigint = &u64_4_to_biguint(&b_c1); + + let _a_c0: [u64; 4] = a_c0_bigint.to_u64_digits().try_into().unwrap(); + let _a_c1: [u64; 4] = a_c1_bigint.to_u64_digits().try_into().unwrap(); + let _b_c0: [u64; 4] = b_c0_bigint.to_u64_digits().try_into().unwrap(); + let _b_c1: [u64; 4] = b_c1_bigint.to_u64_digits().try_into().unwrap(); + + assert_eq!(a_c0, _a_c0); + assert_eq!(a_c1, _a_c1); + assert_eq!(b_c0, _b_c0); + assert_eq!(b_c1, _b_c1); + + // Fp2 Addition test + let c0 = (a_c0_bigint + b_c0_bigint) % &modulus; + let c1 = (a_c1_bigint + b_c1_bigint) % &modulus; + + let (res_c0, res_c1) = fp2_add(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_4_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_4_to_biguint(&res_c1) % &modulus); + + // Fp2 Subtraction test + let c0 = (a_c0_bigint + &modulus - b_c0_bigint) % &modulus; + let c1 = (a_c1_bigint + &modulus - b_c1_bigint) % &modulus; + + let (res_c0, res_c1) = fp2_sub(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_4_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_4_to_biguint(&res_c1) % &modulus); + } + + println!("All tests passed!"); +} diff --git a/tests/bn254-fp2-mul/Cargo.lock b/tests/bn254-fp2-mul/Cargo.lock new file mode 100644 index 0000000000..dc82714d82 --- /dev/null +++ b/tests/bn254-fp2-mul/Cargo.lock @@ -0,0 +1,317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bn254-fp2-mul-test" +version = "1.1.1" +dependencies = [ + "num-bigint", + "rand", + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sp1-derive" +version = "1.1.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-lib" +version = "1.1.1" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "serde", +] + +[[package]] +name = "sp1-zkvm" +version = "1.1.1" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "sp1-lib", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/tests/bn254-fp2-mul/Cargo.toml b/tests/bn254-fp2-mul/Cargo.toml new file mode 100644 index 0000000000..9c904ef57b --- /dev/null +++ b/tests/bn254-fp2-mul/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +[package] +name = "bn254-fp2-mul-test" +version = "1.1.1" +edition = "2021" +publish = false + + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } +num-bigint = "0.4.6" +rand = "0.8.5" diff --git a/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..6e08b1d49a Binary files /dev/null and b/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp2-mul/src/main.rs b/tests/bn254-fp2-mul/src/main.rs new file mode 100644 index 0000000000..1ab8b81bdb --- /dev/null +++ b/tests/bn254-fp2-mul/src/main.rs @@ -0,0 +1,97 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use num_bigint::BigUint; +use rand::Rng; +use sp1_zkvm::lib::syscall_bn254_fp2_mulmod; +use std::{mem::transmute, str::FromStr}; + +const MODULUS: &str = + "21888242871839275222246405745257275088696311157297823662689037894645226208583"; + +fn random_u64_4(modulus: &BigUint) -> [u64; 4] { + let mut rng = rand::thread_rng(); + let mut arr = [0u64; 4]; + let modulus_bytes = modulus.to_bytes_le(); + let modulus_u64: [u64; 4] = [ + u64::from_le_bytes(modulus_bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(modulus_bytes[24..32].try_into().unwrap()), + ]; + + for i in 0..4 { + arr[i] = rng.gen_range(0..modulus_u64[i]); + } + arr +} + +fn u64_4_to_biguint(arr: &[u64; 4]) -> BigUint { + let mut bytes = [0u8; 32]; + for i in 0..4 { + bytes[i * 8..(i + 1) * 8].copy_from_slice(&arr[i].to_le_bytes()); + } + BigUint::from_bytes_le(&bytes) +} + +fn fp2_mul( + lhs_c0: &[u64; 4], + lhs_c1: &[u64; 4], + rhs_c0: &[u64; 4], + rhs_c1: &[u64; 4], +) -> ([u64; 4], [u64; 4]) { + let lhs = [lhs_c0.clone(), lhs_c1.clone()].concat(); + let rhs = [rhs_c0.clone(), rhs_c1.clone()].concat(); + + let mut lhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(lhs.try_into().unwrap()) }; + let rhs_transmuted: [u32; 16] = + unsafe { transmute::<[u64; 8], [u32; 16]>(rhs.try_into().unwrap()) }; + + unsafe { + syscall_bn254_fp2_mulmod(lhs_transmuted.as_mut_ptr(), rhs_transmuted.as_ptr()); + } + + let result_c0: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[0..8].try_into().unwrap()) }; + let result_c1: [u64; 4] = + unsafe { transmute::<[u32; 8], [u64; 4]>(lhs_transmuted[8..16].try_into().unwrap()) }; + + (result_c0, result_c1) +} + +pub fn main() { + let modulus = BigUint::from_str(MODULUS).unwrap(); + + for _ in 0..10 { + let a_c0 = random_u64_4(&modulus); + let a_c1 = random_u64_4(&modulus); + let b_c0 = random_u64_4(&modulus); + let b_c1 = random_u64_4(&modulus); + + let a_c0_bigint = u64_4_to_biguint(&a_c0); + let a_c1_bigint = u64_4_to_biguint(&a_c1); + let b_c0_bigint = u64_4_to_biguint(&b_c0); + let b_c1_bigint = u64_4_to_biguint(&b_c1); + + let ac0_bc0_mod = (&a_c0_bigint * &b_c0_bigint) % &modulus; + let ac1_bc1_mod = (&a_c1_bigint * &b_c1_bigint) % &modulus; + + let c0 = if ac0_bc0_mod < ac1_bc1_mod { + (&modulus + ac0_bc0_mod - ac1_bc1_mod) % &modulus + } else { + (ac0_bc0_mod - ac1_bc1_mod) % &modulus + }; + + let c1 = ((&a_c0_bigint * &b_c1_bigint) % &modulus + + (&a_c1_bigint * &b_c0_bigint) % &modulus) + % &modulus; + + let (res_c0, res_c1) = fp2_mul(&a_c0, &a_c1, &b_c0, &b_c1); + + assert_eq!(c0, u64_4_to_biguint(&res_c0) % &modulus); + assert_eq!(c1, u64_4_to_biguint(&res_c1) % &modulus); + } + + println!("All tests passed!"); +} diff --git a/tests/ecrecover/Cargo.toml b/tests/ecrecover/Cargo.toml deleted file mode 100644 index eab2009709..0000000000 --- a/tests/ecrecover/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[workspace] -[package] -name = "ecrecover-test" -version = "1.1.0" -edition = "2021" -publish = false - -[dependencies] -sp1-zkvm = { path = "../../zkvm/entrypoint", features = ["secp256k1"] } -hex-literal = "0.4.1" -num = { version = "0.4.1", default-features = false } -k256 = { version = "0.13.3", features = ["ecdsa"] } diff --git a/tests/ecrecover/elf/riscv32im-succinct-zkvm-elf b/tests/ecrecover/elf/riscv32im-succinct-zkvm-elf deleted file mode 100755 index 8d82912412..0000000000 Binary files a/tests/ecrecover/elf/riscv32im-succinct-zkvm-elf and /dev/null differ diff --git a/tests/ecrecover/src/main.rs b/tests/ecrecover/src/main.rs deleted file mode 100644 index 0de8192a95..0000000000 --- a/tests/ecrecover/src/main.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![no_main] -sp1_zkvm::entrypoint!(main); - -use hex_literal::hex; -use sp1_zkvm::lib::io; -use sp1_zkvm::lib::secp256k1::ecrecover; - -pub fn main() { - // recovery param: 1 - // message: 5c868fedb8026979ebd26f1ba07c27eedf4ff6d10443505a96ecaf21ba8c4f0937b3cd23ffdc3dd429d4cd1905fb8dbcceeff1350020e18b58d2ba70887baa3a9b783ad30d3fbf210331cdd7df8d77defa398cdacdfc2e359c7ba4cae46bb74401deb417f8b912a1aa966aeeba9c39c7dd22479ae2b30719dca2f2206c5eb4b7 - // pubkey compressed: 034a071e8a6e10aada2b8cf39fa3b5fb3400b04e99ea8ae64ceea1a977dbeaf5d5 - // pubkey: 044a071e8a6e10aada2b8cf39fa3b5fb3400b04e99ea8ae64ceea1a977dbeaf5d5f8c8fbd10b71ab14cd561f7df8eb6da50f8a8d81ba564342244d26d1d4211595 - - let msg_hash = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0"); - let sig = hex!( - "45c0b7f8c09a9e1f1cea0c25785594427b6bf8f9f878a8af0b1abbb48e16d0920d8becd0c220f67c51217eecfd7184ef0732481c843857e6bc7fc095c4f6b78801" - ); - - let pubkey = ecrecover(&sig, &msg_hash).unwrap(); - io::commit_slice(&pubkey); - println!("pubkey: {:?}", pubkey); -} diff --git a/tests/uint256-mul/Cargo.lock b/tests/uint256-mul/Cargo.lock index 298f5d8d10..d202f1b3ec 100644 --- a/tests/uint256-mul/Cargo.lock +++ b/tests/uint256-mul/Cargo.lock @@ -16,7 +16,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "biguint-mul-test" -version = "0.1.0" +version = "1.0.1" dependencies = [ "bytemuck", "num", @@ -289,7 +289,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "0.1.0" +version = "1.0.1" dependencies = [ "proc-macro2", "quote", @@ -298,7 +298,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "0.1.0" +version = "1.0.1" dependencies = [ "anyhow", "bincode", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "0.1.0" +version = "1.0.1" dependencies = [ "bincode", "cfg-if", diff --git a/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf b/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf index dcf3474c24..2bac42edfc 100755 Binary files a/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/zkvm/lib/src/verify.rs b/zkvm/lib/src/verify.rs deleted file mode 100644 index e9b4c1bfeb..0000000000 --- a/zkvm/lib/src/verify.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::syscall_verify_sp1_proof; - -/// Verifies the next proof in the proof input stream given a pkey digest and public values digest. -/// -/// Note: sp1_zkvm must also have feature `verify` enabled for this function to work. -pub fn verify_sp1_proof(pkey_digest: &[u32; 8], pv_digest: &[u8; 32]) { - unsafe { - syscall_verify_sp1_proof(pkey_digest, pv_digest); - } -}