From 14827132980784524337f21b8d100222b1d6c1a1 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 13:59:31 +0500 Subject: [PATCH 01/20] feat!: replace CRISP RISC Zero proving with OpenVM Make OpenVM the default compute backend for CRISP. The support service runs the Secure Process in an OpenVM guest, and a separate worker generates the application proof, the recursive aggregate and the Halo2 EVM proof. Remove the legacy prover configuration and dependencies, and require explicit checked verifier bindings (OpenVmReceiptVerifier, OpenVmBfvCiphertextVerifier). Keep deployment-local artifacts and test data outside Git. This squashes feat/openvm-integration onto current main. Conflicts with main since 2026-09-19 are resolved to keep both sides: compute batching from main and phase observation from this branch in ComputeInput, main's CI change filters, main's scheduler defaults in the configs, and main's restructured docs and harness docs with the OpenVM wording applied. --- .dockerignore | 1 + .gitattributes | 2 + .github/workflows/ci.yml | 18 +- .github/workflows/releases.yml | 2 +- .gitignore | 12 +- .gitmodules | 6 - Cargo.lock | 188 +- README.md | 2 +- agent/CRATES_ARCHITECTURE.md | 21 + agent/flow-trace/00_INDEX.md | 14 +- agent/flow-trace/04_DKG_AND_COMPUTATION.md | 49 +- agent/flow-trace/08_DATA_AVAILABILITY.md | 23 +- agent/invariants/01_PROTOCOL_ONCHAIN.md | 5 +- agent/invariants/02_CRYPTO_CIRCUITS.md | 11 +- agent/invariants/04_BUILD_CONFIG.md | 23 +- crates/bfv-client/Cargo.toml | 3 + crates/bfv-client/src/client.rs | 20 + crates/cli/src/program.rs | 10 - crates/compute-provider/Cargo.toml | 5 +- crates/compute-provider/Readme.md | 8 +- crates/compute-provider/src/compute_input.rs | 34 +- crates/compute-provider/src/hashing.rs | 32 + crates/compute-provider/src/lib.rs | 1 + crates/config/src/app_config.rs | 17 +- crates/config/src/program_config.rs | 108 +- crates/init/src/container_permissions.rs | 126 - crates/init/src/file_utils.rs | 33 - crates/init/src/git.rs | 30 - crates/init/src/lib.rs | 67 +- crates/init/src/package_json.rs | 74 +- crates/safe/Cargo.toml | 12 +- crates/safe/src/lib.rs | 6 + crates/safe/src/poseidon2_accel.rs | 416 +- crates/scripts/update_revs.sh | 1 - crates/support-scripts/ctl/compile | 4 - crates/support-scripts/ctl/container | 88 - crates/support-scripts/ctl/shell | 4 - crates/support-scripts/ctl/start | 80 - crates/support-scripts/ctl/upload | 26 - crates/support-scripts/src/lib.rs | 17 +- crates/support-scripts/src/program.rs | 38 +- crates/support-scripts/src/program_dev.rs | 8 - crates/support-scripts/src/program_openvm.rs | 51 + crates/support-scripts/src/program_risc0.rs | 111 - crates/support-scripts/src/traits.rs | 1 - crates/support-scripts/tests/container.sh | 199 - crates/support/Cargo.lock | 4418 ++--------- crates/support/Cargo.toml | 39 +- crates/support/Dockerfile | 79 +- crates/support/README.md | 399 +- crates/support/app/Cargo.toml | 5 - crates/support/app/src/main.rs | 64 +- crates/support/host/Cargo.toml | 20 +- crates/support/host/README.md | 13 +- crates/support/host/src/bin/profile_risc0.rs | 102 - crates/support/host/src/lib.rs | 904 +-- crates/support/methods/Cargo.toml | 18 - crates/support/methods/README.md | 29 - crates/support/methods/build.rs | 192 - .../support/methods/guest-builder.Dockerfile | 11 - crates/support/methods/guest/Cargo.toml | 43 - crates/support/methods/guest/README.md | 12 - .../support/methods/guest/src/bin/program.rs | 25 - crates/support/methods/src/lib.rs | 22 - crates/support/openvm/README.md | 166 + crates/support/openvm/fhe-optimizations.patch | 403 + .../{methods => openvm}/guest/Cargo.lock | 1844 +++-- crates/support/openvm/guest/Cargo.toml | 29 + crates/support/openvm/guest/openvm.toml | 7 + crates/support/openvm/guest/src/main.rs | 35 + crates/support/openvm/prover/Cargo.lock | 6516 +++++++++++++++++ crates/support/openvm/prover/Cargo.toml | 21 + crates/support/openvm/prover/src/main.rs | 256 + crates/support/program/Cargo.toml | 9 + crates/support/scripts/build.sh | 3 +- crates/support/scripts/container/build.sh | 4 +- crates/support/scripts/container/start.sh | 85 +- crates/support/scripts/container/upload.sh | 129 - crates/support/scripts/dev.sh | 16 - crates/support/types/src/lib.rs | 22 + crates/zk-helpers/src/circuits/commitments.rs | 30 +- crates/zk-helpers/src/packing.rs | 179 +- eslint.config.mjs | 6 +- examples/CRISP/.gitignore | 4 +- examples/CRISP/Cargo.lock | 116 +- examples/CRISP/Readme.md | 86 +- examples/CRISP/eslint.config.js | 4 +- examples/CRISP/interfold.config.yaml | 20 +- .../CRISP/packages/crisp-contracts/README.md | 6 +- .../contracts/CRISPProgram.sol | 32 +- ...ier.sol => MockComputeReceiptVerifier.sol} | 6 +- .../Mocks/RiscZeroGroth16Verifier.sol | 13 - .../contracts/test/MockOpenVmCallVerifier.sol | 20 + .../deploy/create-governance-builder.ts | 4 +- .../packages/crisp-contracts/deploy/crisp.ts | 77 +- .../crisp-contracts/hardhat.config.ts | 8 +- .../crisp-contracts/lib/risc0-ethereum | 1 - .../packages/crisp-contracts/package.json | 2 +- .../packages/crisp-contracts/remappings.txt | 4 +- .../tests/crisp.journal.test.ts | 42 +- .../tests/openvm-proof.test.ts | 81 + .../tests/openvm-receipt.test.ts | 189 + .../tests/openvm-service.test.ts | 373 + .../packages/crisp-contracts/tests/utils.ts | 14 +- examples/CRISP/program/Cargo.toml | 5 + examples/CRISP/program/README.md | 101 +- .../CRISP/program/examples/openvm_fixture.rs | 130 + examples/CRISP/program/src/lib.rs | 13 +- .../CRISP/program/tests/secure_process.rs | 2 +- examples/CRISP/scripts/dev_program.sh | 2 +- examples/CRISP/server/.env.example | 4 +- examples/CRISP/server/Dockerfile | 2 - examples/CRISP/server/Readme.md | 2 +- .../server/src/server/data_availability.rs | 2 +- examples/CRISP/server/src/server/indexer.rs | 4 +- examples/CRISP/server/src/server/mod.rs | 9 +- examples/CRISP/server/src/server/payloads.rs | 61 + .../CRISP/server/src/server/routes/state.rs | 6 +- .../CRISP/server/src/server/routes/voting.rs | 6 +- package.json | 1 + .../interfaces/IOpenVmReceiptVerifier.sol | 11 + .../contracts/lib/OpenVmComputeProof.sol | 44 + .../verifiers/OpenVmReceiptVerifier.sol | 94 + .../bfv/OpenVmBfvCiphertextVerifier.sol | 87 + packages/interfold-contracts/scripts/index.ts | 1 + .../interfold-contracts/scripts/openVm.ts | 100 + .../scripts/protocol/types.ts | 2 +- .../test/Deployment/OpenVm.spec.ts | 112 + .../test/fixtures/system.ts | 72 +- packages/interfold-sdk/src/utils.ts | 2 +- packages/interfold-sdk/tests/utils.test.ts | 14 + pnpm-lock.yaml | 8 - scripts/README.md | 16 +- scripts/clean.ts | 1 - scripts/generate-provenance-manifest.ts | 486 +- scripts/run-openvm.sh | 55 + scripts/setup-openvm-fhe.mjs | 31 + templates/default/.gitignore | 3 +- templates/default/.gitignore.bak | 4 - templates/default/.gitmodules.bak | 3 - .../generated/contracts/ImageID.sol | 23 - templates/default/Cargo.lock | 27 - templates/default/README.md | 40 +- .../Mocks/MockOpenVmReceiptVerifier.sol | 14 + .../contracts/Mocks/MockRISC0Verifier.sol | 14 - templates/default/contracts/MyProgram.sol | 16 +- templates/default/deploy/default.ts | 40 +- templates/default/eslint.config.js | 2 - templates/default/hardhat.config.ts | 9 +- templates/default/interfold.config.yaml | 21 +- templates/default/lib/risc0-ethereum | 1 - templates/default/package.json | 3 +- templates/default/remappings.txt | 1 - templates/default/scripts/dev_ciphernodes.sh | 5 - templates/default/scripts/setup.sh | 6 +- templates/default/scripts/test_integration.sh | 2 + tests/integration/interfold.config.yaml | 17 +- 157 files changed, 12148 insertions(+), 8853 deletions(-) create mode 100644 .gitattributes delete mode 100644 .gitmodules create mode 100644 crates/compute-provider/src/hashing.rs delete mode 100644 crates/init/src/container_permissions.rs delete mode 100755 crates/support-scripts/ctl/compile delete mode 100755 crates/support-scripts/ctl/container delete mode 100755 crates/support-scripts/ctl/shell delete mode 100755 crates/support-scripts/ctl/start delete mode 100755 crates/support-scripts/ctl/upload create mode 100644 crates/support-scripts/src/program_openvm.rs delete mode 100644 crates/support-scripts/src/program_risc0.rs delete mode 100755 crates/support-scripts/tests/container.sh delete mode 100644 crates/support/host/src/bin/profile_risc0.rs delete mode 100644 crates/support/methods/Cargo.toml delete mode 100644 crates/support/methods/README.md delete mode 100644 crates/support/methods/build.rs delete mode 100644 crates/support/methods/guest-builder.Dockerfile delete mode 100644 crates/support/methods/guest/Cargo.toml delete mode 100644 crates/support/methods/guest/README.md delete mode 100644 crates/support/methods/guest/src/bin/program.rs delete mode 100644 crates/support/methods/src/lib.rs create mode 100644 crates/support/openvm/README.md create mode 100644 crates/support/openvm/fhe-optimizations.patch rename crates/support/{methods => openvm}/guest/Cargo.lock (72%) create mode 100644 crates/support/openvm/guest/Cargo.toml create mode 100644 crates/support/openvm/guest/openvm.toml create mode 100644 crates/support/openvm/guest/src/main.rs create mode 100644 crates/support/openvm/prover/Cargo.lock create mode 100644 crates/support/openvm/prover/Cargo.toml create mode 100644 crates/support/openvm/prover/src/main.rs delete mode 100755 crates/support/scripts/container/upload.sh delete mode 100755 crates/support/scripts/dev.sh rename examples/CRISP/packages/crisp-contracts/contracts/Mocks/{MockRISC0Verifier.sol => MockComputeReceiptVerifier.sol} (77%) delete mode 100644 examples/CRISP/packages/crisp-contracts/contracts/Mocks/RiscZeroGroth16Verifier.sol create mode 100644 examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmCallVerifier.sol delete mode 160000 examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum create mode 100644 examples/CRISP/packages/crisp-contracts/tests/openvm-proof.test.ts create mode 100644 examples/CRISP/packages/crisp-contracts/tests/openvm-receipt.test.ts create mode 100644 examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts create mode 100644 examples/CRISP/program/examples/openvm_fixture.rs create mode 100644 examples/CRISP/server/src/server/payloads.rs create mode 100644 packages/interfold-contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol create mode 100644 packages/interfold-contracts/contracts/lib/OpenVmComputeProof.sol create mode 100644 packages/interfold-contracts/contracts/verifiers/OpenVmReceiptVerifier.sol create mode 100644 packages/interfold-contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol create mode 100644 packages/interfold-contracts/scripts/openVm.ts create mode 100644 packages/interfold-contracts/test/Deployment/OpenVm.spec.ts create mode 100644 packages/interfold-sdk/tests/utils.test.ts create mode 100644 scripts/run-openvm.sh create mode 100644 scripts/setup-openvm-fhe.mjs delete mode 100644 templates/default/.gitmodules.bak delete mode 100644 templates/default/.interfold/generated/contracts/ImageID.sol create mode 100644 templates/default/contracts/Mocks/MockOpenVmReceiptVerifier.sol delete mode 100644 templates/default/contracts/Mocks/MockRISC0Verifier.sol delete mode 160000 templates/default/lib/risc0-ethereum diff --git a/.dockerignore b/.dockerignore index 6000c736f3..2e8880000a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,7 @@ !Cargo.toml !Cargo.lock !crates/**/* +!examples/CRISP/program/**/* !packages/**/* !package.json !pnpm-workspace.yaml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..f8be7e3177 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Unified diff context lines can contain a single space. +crates/support/openvm/fhe-optimizations.patch -whitespace diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4011f79b9c..d1ce2fe2b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,7 +289,8 @@ jobs: echo "templates=$(any $FORCE $TEMPLATES $RUST $CONTRACTS $CIRCUITS $SDK $CI $TOOLING)" >> $GITHUB_OUTPUT echo "zk=$(any $FORCE $RUST $CIRCUITS $CI $TOOLING)" >> $GITHUB_OUTPUT echo "contracts=$(any $FORCE $CONTRACTS $CI $TOOLING)" >> $GITHUB_OUTPUT - echo "docker_support=$(any $FORCE $DOCKER $CI)" >> $GITHUB_OUTPUT + # The OpenVM service compiles repository-local Rust and CRISP program sources. + echo "docker_support=$(any $FORCE $DOCKER $RUST $CRISP_RUST $CI)" >> $GITHUB_OUTPUT # The rust jobs already compile the workspace, so the image build only # needs to run when the Dockerfiles or their build context change. echo "docker_ciphernode=$(any $FORCE $DOCKER $CI)" >> $GITHUB_OUTPUT @@ -590,16 +591,15 @@ jobs: curl --fail --silent --head --retry 10 --retry-connrefused --retry-delay 1 "$E3_TEST_CIRCUITS_DOWNLOAD_URL" >/dev/null cargo test -p e3-zk-prover --features integration-tests --test integration_tests -- --nocapture - # Guards the RISC Zero guest artifact. The on-chain imageId is immutable, so a guest change - # that leaves ImageID.sol untouched ships a verifier that no longer matches this tree. - build_e3_support_risc0: + # Build the native OpenVM HTTP service. Proving artifacts are deployment-specific. + build_e3_support_openvm: needs: [detect_changes] if: needs.detect_changes.outputs.docker_support == 'true' timeout-minutes: 30 runs-on: ${{ github.repository == 'theinterfold/interfold' && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && format('runs-on={0}-{1}-{2}/runner=4cpu-linux-x64/ram=16/spot=false', github.run_id, - github.run_attempt, 'build_e3_support_risc0') || 'ubuntu-latest' }} + github.run_attempt, 'build_e3_support_openvm') || 'ubuntu-latest' }} permissions: contents: read packages: write @@ -630,7 +630,7 @@ jobs: - name: Build image uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: - context: ./crates/support + context: . file: ${{ env.SUPPORT_DOCKERFILE_PATH }} push: ${{ github.ref == 'refs/heads/main' }} tags: ${{ steps.tags.outputs.tags }} @@ -1573,8 +1573,6 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: submodules: recursive - - name: Test support image resolution - run: bash crates/support-scripts/tests/container.sh - name: Cache Rust dependencies uses: ./.github/actions/cache-dependencies with: @@ -1586,6 +1584,8 @@ jobs: toolchain: ${{ env.RUST_TOOLCHAIN }} - name: Install protoc run: sudo apt-get update -y && sudo apt-get install -y protobuf-compiler + - name: Test program backend selection + run: cargo test --locked -p e3-support-scripts - name: Build support scripts run: cd templates/default && cargo build --locked --bin e3-support-scripts-dev - name: Verify build artifacts @@ -1843,8 +1843,6 @@ jobs: run: | cd templates/default pnpm compile - chmod 755 .interfold/generated/contracts tests - chmod 644 .interfold/generated/contracts/ImageID.sol pnpm test:integration test_interfold_init: diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 66e6311a3b..254f7122ac 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -105,7 +105,7 @@ jobs: - name: Build & push e3-support release image uses: docker/build-push-action@v5 with: - context: ./crates/support + context: . file: ${{ env.SUPPORT_DOCKERFILE_PATH }} push: true tags: | diff --git a/.gitignore b/.gitignore index 6b0311c16b..d51aabb1fa 100644 --- a/.gitignore +++ b/.gitignore @@ -19,12 +19,18 @@ __pycache__/ # circuit benchmarks circuits/benchmarks/results_*/raw/ -# Generated by crates/support/methods/build.rs. Holds a machine-local guest ELF path, -# so it is never committed. -crates/support/tests/Elf.sol +# Local dependency checkouts are not part of the program source. +templates/default/lib/ +examples/CRISP/packages/crisp-contracts/lib/ .vercel .vercel-env-backups/ +# Deployment-local OpenVM settings and generated proving artifacts. +openvm-prover.local.json +*.vmexe +*.proof +*.proof.json + # agent working files .hermes/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 281f92acc3..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum"] - path = examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum - url = https://github.com/risc0/risc0-ethereum -[submodule "templates/default/lib/risc0-ethereum"] - path = templates/default/lib/risc0-ethereum - url = https://github.com/gnosisguild/risc0-ethereum diff --git a/Cargo.lock b/Cargo.lock index 6f486e58a4..ac39eb1ee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3825,6 +3825,7 @@ dependencies = [ "light-poseidon", "num-bigint 0.4.6", "num-traits", + "openvm-keccak256", "rand 0.9.5", "rand_chacha 0.9.0", "rayon", @@ -4400,9 +4401,12 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", + "num-bigint 0.4.6", + "openvm", + "openvm-algebra-guest", "rand 0.9.5", "rand_chacha 0.9.0", - "risc0-bigint2", + "serde", "sha3", "taceo-poseidon2", ] @@ -6221,12 +6225,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "include_bytes_aligned" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" - [[package]] name = "indenter" version = "0.3.4" @@ -7876,6 +7874,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.5", ] [[package]] @@ -7954,6 +7953,33 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-prime" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e238432a7881ec7164503ccc516c014bf009be7984cde1ba56837862543bdec3" +dependencies = [ + "bitvec", + "either", + "lru 0.12.5", + "num-bigint 0.4.6", + "num-integer", + "num-modular", + "num-traits", + "rand 0.8.5", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -8215,6 +8241,113 @@ dependencies = [ "tracing", ] +[[package]] +name = "openvm" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "bytemuck", + "getrandom 0.2.17", + "getrandom 0.3.4", + "num-bigint 0.4.6", + "openvm-custom-insn", + "openvm-platform", + "openvm-rv32im-guest", + "serde", +] + +[[package]] +name = "openvm-algebra-complex-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-macros-common", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openvm-algebra-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint 0.4.6", + "once_cell", + "openvm-algebra-complex-macros", + "openvm-algebra-moduli-macros", + "openvm-custom-insn", + "openvm-rv32im-guest", + "serde-big-array", + "strum_macros 0.26.4", +] + +[[package]] +name = "openvm-algebra-moduli-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint 0.4.6", + "num-prime", + "openvm-macros-common", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openvm-keccak256" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-keccak256-guest", + "spin 0.10.1", + "tiny-keccak", +] + +[[package]] +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-macros-common" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "syn 2.0.117", +] + +[[package]] +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "libm", + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros 0.26.4", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -9429,16 +9562,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "risc0-bigint2" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87f5f7494a2242cead2750b7ce2b8522c1be83dee268479f1c12ed521eaf595" -dependencies = [ - "include_bytes_aligned", - "stability", -] - [[package]] name = "rlp" version = "0.5.2" @@ -10725,6 +10848,12 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" + [[package]] name = "spki" version = "0.7.3" @@ -10745,16 +10874,6 @@ dependencies = [ "der 0.8.1", ] -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.117", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -10798,6 +10917,19 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +[[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.117", +] + [[package]] name = "strum_macros" version = "0.27.2" @@ -11951,7 +12083,7 @@ dependencies = [ "num-derive", "num-traits", "smallvec", - "spin", + "spin 0.9.9", "wasmi_collections", "wasmi_core", "wasmparser-nostd", diff --git a/README.md b/README.md index 5a45a73d86..d02ac550b6 100644 --- a/README.md +++ b/README.md @@ -301,7 +301,7 @@ sequenceDiagram CRISPServer->>E3Program: finalizeInput(e3Id, VectorX receipt) E3Program-->>CRISPServer: InputPublished - ComputeProvider-->>CRISPServer: aggregateCiphertext + RISC Zero proof + ComputeProvider-->>CRISPServer: aggregateCiphertext + OpenVM proof CRISPServer->>E3Program: verify output proof (read only) CRISPServer->>Avail: submit_data(aggregateCiphertext) CRISPServer->>Interfold: publishCiphertextOutput(e3Id, reference + VectorX receipt) diff --git a/agent/CRATES_ARCHITECTURE.md b/agent/CRATES_ARCHITECTURE.md index 27e3e4b407..2c3603714a 100644 --- a/agent/CRATES_ARCHITECTURE.md +++ b/agent/CRATES_ARCHITECTURE.md @@ -1397,3 +1397,24 @@ New E3s start from zero; terminal or finalized E3 checkpoints are removed. Extension points should be narrow concrete boundaries with an active consumer: repository factories, network interfaces, ZK backends, sortition backends, clocks, and task pools. New one-method traits are not introduced solely to create layers. + +### OpenVM compute support + +The isolated `crates/support` workspace serves CRISP compute requests. Its native host calls the +separate `crates/support/openvm/prover` worker and accepts only a verified OpenVM EVM receipt. +The guest and host share the canonical CRISP policy source. The normal `e3-support-scripts` +backend uses `program.openvm`; it no longer selects RISC Zero or Boundless. +The worker validates the executable, VM identity, aggregation key, verifier artifact, and journal. +Jobs remain in memory; this service does not provide durable admission or restart recovery. +`interfold program compile` builds the native service. Guest compilation and key preparation are +separate steps. The CLI has no program-upload or container-shell command. `e3-init` does not install +an external verifier submodule or copy the old container controls. `program.dev` is an explicit, +unproved runner; normal startup requires the OpenVM configuration. + +CRISP's encrypted-input and result-callback routes accept at most 4 MiB of JSON, to contain the +largest supported DA object after hexadecimal encoding. This limit is scoped to those routes; +read routes retain their smaller default limit. `CRISP_BIND_ADDR` selects the HTTP listener and +defaults to `0.0.0.0:4000`. +The server starts a multithread Tokio runtime. Input validation and large round-record updates must +not prevent the RPC transports from receiving WebSocket heartbeats. Actix HTTP workers retain their +own runtimes; the server does not use Actix actors or `actix_web::rt::spawn`. diff --git a/agent/flow-trace/00_INDEX.md b/agent/flow-trace/00_INDEX.md index cd71a40d4c..d1cfda99dd 100644 --- a/agent/flow-trace/00_INDEX.md +++ b/agent/flow-trace/00_INDEX.md @@ -422,6 +422,16 @@ Findings in the ballot path of the reference app (`examples/CRISP`), not the pro | **A dropped ballot was reported as cast** | Partial | Clients reported success at commitment, but an earlier sibling on the same parent takes the slot. `POST /voting/selection` reports whether the input is selected, and the CRISP client shows each stage, marks the round as voted only at `counted`, and offers a new proof before the commitment deadline. The governance apps do not run the check. | | **Access logs linked callers to jobs** | Fixed | The access log records the method and the matched route template (`access_logger`), not the caller address or the request path that carries a job ID. | +### Local RPC subscription limitation + +The pinned Hardhat 3.0.11 node uses EDR 0.12.0-next.10, which removes expired filters without +excluding subscriptions. The deadline is five minutes. A CRISP listener can therefore stop receiving +blocks and logs while its WebSocket remains open. This prevents automatic compute dispatch or result +indexing in long local rounds. Use Anvil for the live OpenVM service test. This limitation is not a +proof-verification failure. See the pinned EDR +[filter deadline](https://github.com/NomicFoundation/edr/blob/%40nomicfoundation%2Fedr%400.12.0-next.10/crates/edr_provider/src/filter.rs) +and [subscription cleanup](https://github.com/NomicFoundation/edr/blob/%40nomicfoundation%2Fedr%400.12.0-next.10/crates/edr_provider/src/data.rs). + ### Protocol Design Concerns | # | Concern | Severity | Detail | @@ -510,10 +520,10 @@ Findings in the ballot path of the reference app (`examples/CRISP`), not the pro | Z-09 | **Failure grace authority (Zenith #9)** | Resolved | The failure grace period recognizes only active finalized committee members. Expelled members and provisional candidates have no committee authority. | | Z-10 | **Failure reason sentinel (Zenith #10)** | Resolved | Interfold rejects `None`, the failure-reason sentinel, and larger values from authorized dependencies before it changes the E3 stage. | | Z-14 | **Late DKG publication (Zenith #14)** | Resolved | Committee key publication remains valid through the DKG deadline. Interfold rejects later publication and preserves supplier-side timeout attribution. | -| Z-15 | **Protocol-owned ciphertext verification (Zenith #15)** | Resolved | Each E3 snapshots an owner-configured verifier and BFV parameter hash for its encryption scheme. Before `CiphertextReady`, that verifier checks the compute receipt against the chain ID, Interfold address, E3 ID, scheme ID, parameter hash, committee public key hash, output hash, and SAFE commitment. The application program remains a separate verification gate, so an always-true program cannot create an unproven decryption duty. The RISC Zero wrapper rejects a receipt-verifier address without deployed code. | +| Z-15 | **Protocol-owned ciphertext verification (Zenith #15)** | Resolved | Each E3 snapshots an owner-configured verifier and BFV parameter hash for its encryption scheme. Before `CiphertextReady`, that verifier checks the compute receipt against the chain ID, Interfold address, E3 ID, scheme ID, parameter hash, committee public key hash, output hash, and SAFE commitment. The application program remains a separate verification gate, so an always-true program cannot create an unproven decryption duty. The OpenVM and legacy RISC Zero wrappers reject a receipt-verifier address without deployed code. | | Z-17 | **Pre-TGE minting lifecycle (Zenith #17)** | Resolved | Token comments, lifecycle documentation, and boundary tests now match the intended behavior. Authorized minting remains available until TGE, including CCA and Cooldown. | | Z-18 | **Scoped launcher transfer access (Zenith #18)** | Resolved | The sale deployer grants the LiquidityLauncher temporary pre-TGE transfer access only for distribution, then revokes it before handing FOLD ownership to the Safe. The LBP strategy and position manager retain the access needed for later liquidity operations. | -| Z-19 | **Ciphertext commitment binding (Zenith #19)** | Resolved | Every E3 program receives the SAFE commitment during verification. The CRISP program and starter template include it in the RISC Zero journal. | +| Z-19 | **Ciphertext commitment binding (Zenith #19)** | Resolved | Every E3 program receives the SAFE commitment during verification. The CRISP program and starter template include it in the OpenVM journal. | | Z-20 | **Stable reward eligibility during slashing (Zenith #20)** | Resolved | Slash routes preserve their proposal, target, token, and amount. A target cannot receive its own penalty proceeds. An unresolved expulsion holds the accused operator's unclaimed fee and slash-funded shares, including a base share calculated before the proposal opened. Clearance releases those shares, while execution reallocates them without blocking peer claims. A reward claimed before the proposal opened remains final. | | Z-22 | **Provisional committee membership (Zenith #22)** | Resolved | Sortition candidates receive membership only after successful finalization. Failed formation returns no active nodes, so provisional candidates cannot authorize slashes or block refunds. | | Z-25 | **Exact custody-asset accounting (Zenith #25)** | Resolved | Fee and bonding assets must transfer exact amounts and must not rebase balances. Inbound transfers verify the custody increase. Outbound transfers verify both the recipient increase and custody decrease, so a sender-paid fee cannot consume another pooled liability. Any mismatch reverts atomically. | diff --git a/agent/flow-trace/04_DKG_AND_COMPUTATION.md b/agent/flow-trace/04_DKG_AND_COMPUTATION.md index 6b52da8269..b0b293baeb 100644 --- a/agent/flow-trace/04_DKG_AND_COMPUTATION.md +++ b/agent/flow-trace/04_DKG_AND_COMPUTATION.md @@ -1124,21 +1124,22 @@ deadlines, recovery flow, and remaining trust. ### Ciphertext Output Publication -The support host sends raw bincode input by default. `BOUNDLESS_INPUT_ENCODING=risc0-serde` selects -the older byte-vector wrapper for an external Boundless guest and requires `PROGRAM_URL`. The -embedded guest always receives raw bincode. This compatibility setting does not change the guest or -its image ID. The selected external guest must match the deployed verifiers and produce the same -journal as the host for the round inputs. - -The RISC Zero guest commits nine 32-byte fields in this order: chain ID, Interfold address, E3 ID, -encryption scheme ID, committee public key, output hash, SAFE commitment, parameter hash, and input -root. RISC Zero serializes these fields as a 1,188-byte journal. The support app returns the seal, -parameter hash, and input root in one ABI-encoded proof. +The support host sends raw bincode input to the OpenVM guest. The native host and guest use the +same CRISP policy source. The guest commits nine 32-byte ABI words in this order: chain ID, +Interfold address, full uint256 E3 ID, encryption scheme ID, committee public-key hash, output hash, +SAFE commitment, parameter hash, and input root. It reveals SHA-256 of these 288 bytes. + +The support worker generates an application proof, recursive aggregate, and Halo2 EVM proof. +It checks the configured executable and VM commitments and verifies the EVM proof against the +native journal before it returns a seal. The app returns the seal, parameter hash, and input root +in one ABI-encoded proof. Missing configuration or a failed proof cannot select a fake-proof mode. +See `crates/support/openvm/README.md` for the build and deployment boundary. Existing RISC Zero +deployment records are not migrated by this source change. The request-time scheme verifier reconstructs the protocol fields from on-chain state. The E3 program reconstructs the application fields from its state. Both contracts verify the same receipt. An application verifier cannot create a decryption duty unless the scheme verifier also accepts it. -The RISC Zero wrapper accepts only a receipt-verifier address that contains deployed code. An EOA +The OpenVM wrapper accepts only a receipt-verifier address that contains deployed code. An EOA cannot satisfy the verifier's void-return call with empty return data. The input root uses the smallest binary Poseidon tree that can hold the submitted SAFE ciphertext commitments, with a minimum depth of one. The compute provider and E3 program must use this same leaf value, order, zero @@ -1149,7 +1150,7 @@ The guest derives the input root from the ciphertexts it processed. `ComputeInpu over those ciphertexts before it builds the tree (`crates/compute-provider/src/compute_input.rs`). The leaves are therefore a function of the processed set, not a separate prover-supplied value. -This binding matters because nothing else supplies it. `Risc0BfvCiphertextVerifier` takes the input +This binding matters because nothing else supplies it. `OpenVmBfvCiphertextVerifier` takes the input root from the proof envelope and never constrains it, so the only check on the root is the comparison an E3 program performs against its own on-chain root (`CRISPProgram.verify`, `MyProgram.verify`). If the guest accepted the leaves as an independent input, that comparison would @@ -1967,18 +1968,22 @@ commitment and every input is computed over — and matches the starter template `MyProgram.publishInput` inserts the commitment directly. Every E3 program exports `policy()` beside `fhe_processor`, so the guest and the dev runner need not know which program they are running. -The published support image embeds the CRISP guest from `crates/support/program`. The reference app -keeps the same guest in `examples/CRISP/program`. A CRISP policy change must update both copies and -regenerate `crates/support/contracts/ImageID.sol` before the support image is published. +The support program manifest points to the canonical CRISP source in `examples/CRISP/program`. +A policy change requires a new OpenVM executable, derived application commitments, and matching +receipt-verifier deployment. Do not reuse a legacy RISC Zero image ID or an aggregation key for +another VM configuration. + +The OpenVM guest enables `heap-embedded-alloc`. A bump allocator never frees, so each input's +temporary Greco form would stay allocated and a secure-preset round would run out of memory as the +round grows. The allocator is part of the guest executable, so changing it changes the application +commitments that the receipt verifiers bind. -The guest links `risc0-zkvm` with `heap-embedded-alloc`. The default bump allocator never frees, so -each input's temporary Greco form stayed allocated and a secure-preset round aborted out of memory -at about 500 inputs. The allocator is part of the guest ELF: changing it changes the image ID, and -`ImageID.sol`, the ciphertext verifier and every deployed `CRISPProgram.imageId` must move with it. +`interfold program start` uses `program.openvm` to locate the repository, worker executable, and +worker configuration. The HTTP service validates this configuration before it accepts work. +Proving artifacts and machine-specific paths stay outside Git. Explicit development mode remains +separate from the real-proof service. -`interfold program start` sends each configured Boundless offer parameter through the project -support launcher to the container. The container maps these values to the environment variables that -build the on-chain offer. An omitted parameter uses the host's built-in default. +File: `examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts` `PublishedData` carries what the program published per input: the stored commitment, and opaque `metadata` the crate never interprets. CRISP puts its 20-byte slot address and the 5-byte parent diff --git a/agent/flow-trace/08_DATA_AVAILABILITY.md b/agent/flow-trace/08_DATA_AVAILABILITY.md index f992332728..ceebbe37c0 100644 --- a/agent/flow-trace/08_DATA_AVAILABILITY.md +++ b/agent/flow-trace/08_DATA_AVAILABILITY.md @@ -9,7 +9,7 @@ uses three different transports: already on Ethereum. - Voter ciphertexts are published to Avail. Ethereum accepts their references only after VectorX proves that the exact bytes were included. -- The aggregate ciphertext uses the same Avail and VectorX receipt, after RISC Zero proves the +- The aggregate ciphertext uses the same Avail and VectorX receipt, after OpenVM proves the computation. Consumers assemble a complete public-key candidate and check its content hash. They decode the key @@ -73,7 +73,7 @@ bytes from Avail, and verify their hash. hash without an accepted VectorX receipt can therefore never enter the final computation. The aggregate callback uses the same two-proof order. Before the server spends Avail funds, it calls -`CRISPProgram.verify` as an Ethereum read with the output hash, SAFE commitment, and RISC Zero +`CRISPProgram.verify` as an Ethereum read with the output hash, SAFE commitment, and OpenVM proof. Only an output that passes that exact on-chain verifier becomes a durable Avail job. The job ID excludes the proof seal, so another valid seal for the same output is an idempotent retry instead of a second paid publication. The job ID also uses the canonical decimal E3 identifier, so an alias @@ -203,7 +203,7 @@ The boundaries are intentional: - The final 3-hour tail accepts no new proof commitments. - `finalizeInput` normally completes in that tail. A delayed receipt can recover while the E3 is still `KeyPublished` and `timestamp <= computeDeadline`. -- RISC Zero does not start at the input-window end while any input is pending. +- OpenVM does not start at the input-window end while any input is pending. - A late `InputPublished` event wakes computation after all pending inputs reach zero. - The aggregate job starts only when more than 3 hours remain before the compute deadline. - Interfold accepts the aggregate output only after the input window ends and no later than the @@ -211,7 +211,7 @@ The boundaries are intentional: Late input finalization is best-effort recovery, not a new seven-day availability promise. The contract can accept a receipt through `computeDeadline`, but the E3 can complete only if enough of -the compute window remains to produce the RISC Zero proof, publish the aggregate ciphertext to +the compute window remains to produce the OpenVM proof, publish the aggregate ciphertext to Avail, wait for its VectorX proof, and submit the output on Ethereum. The server therefore refuses to start an aggregate Avail job unless more than three hours remain. Operators must alert well before that cutoff instead of treating `computeDeadline` as a useful finalization target. @@ -337,7 +337,7 @@ run in the request transaction, before the requester pays the fee. replacement costs one bridge request and no second publication. A job record written before the coordinates were kept decodes with no coordinates, keeps its candidate proof, and needs operator recovery. -- The server verifies an aggregate RISC Zero proof before it creates an Avail output job. An +- The server verifies an aggregate OpenVM proof before it creates an Avail output job. An arbitrary caller of the output webhook cannot spend the Avail account on an invalid output. - The compute server retries a transient callback five times, but this callback is not a durable outbox. If that process exits after it receives a proof but before CRISP accepts the callback, @@ -541,19 +541,20 @@ provider, or on a later adapter, keeps working. ## Fast-machine acceptance gates -The normal unit and contract suites do not reproduce the production RISC Zero image. Before this -branch can deploy, use the durable Interfold revision pinned in both support manifests and run the -pinned Docker build. The generated `ImageID.sol` must be reviewed and then used by both the BFV -ciphertext verifier and CRISP program deployment. A native build is not an acceptable substitute. +The normal unit and contract suites do not reproduce the deployed OpenVM guest. Before deployment, +build the guest and worker from the pinned source and validate their application commitments with +the worker's `check` command. Deploy a checked Halo2 artifact and bind both verification gates to +the same receipt identity. Follow `crates/support/openvm/README.md` and the provenance procedure. +A native computation does not replace this proof check. -After the image is rebuilt, run the full local CRISP Playwright flow and one Sepolia round with real +After the guest is rebuilt, run the full local CRISP Playwright flow and one Sepolia round with real Avail Turing and VectorX. Observe this complete event order: ```text InputCommitted -> Avail finalized -> InputPublished - -> RISC Zero completed + -> OpenVM completed -> aggregate Avail finalized -> CiphertextOutputReferencePublished -> plaintext completion diff --git a/agent/invariants/01_PROTOCOL_ONCHAIN.md b/agent/invariants/01_PROTOCOL_ONCHAIN.md index 08a2e86200..8ec99e2b63 100644 --- a/agent/invariants/01_PROTOCOL_ONCHAIN.md +++ b/agent/invariants/01_PROTOCOL_ONCHAIN.md @@ -236,7 +236,10 @@ every section. CRISP, binds CRISP, and raises the required node protocol version. The partial CRISP-only builder must not run on mainnet. Old nodes become ineligible in the activation transaction. The CRISP program and ciphertext verifier image IDs must both equal the RISC Zero image generated by the - same release source. Requests remain paused until the activation validator succeeds and enough + same release source for that historical activation. OpenVM requires a separate paused, drained + migration with an identity derived from the new guest, VM configuration, and Halo2 verifier; the + RISC Zero activation scripts must not activate it. Requests remain paused until the activation + validator succeeds and enough matching release-ready nodes are online. — `scripts/upgrade/secureCrisp.ts`; `scripts/upgrade/validateSecureCrisp.ts`; `flow-trace/07` - Sortition score must be byte-identical on- and off-chain: diff --git a/agent/invariants/02_CRYPTO_CIRCUITS.md b/agent/invariants/02_CRYPTO_CIRCUITS.md index 8afbcddc26..274a91fc7f 100644 --- a/agent/invariants/02_CRYPTO_CIRCUITS.md +++ b/agent/invariants/02_CRYPTO_CIRCUITS.md @@ -1,7 +1,7 @@ # Invariants — Cryptography / circuits Scope: `circuits/`, `crates/zk-prover`, `crates/zk-helpers`, `crates/trbfv`, `crates/fhe-params`, -the BFV and RISC Zero verifier contracts, `crates/compute-provider`, and the CRISP example. +the BFV and OpenVM receipt verifier contracts, `crates/compute-provider`, and the CRISP example. Committee config sync, Noir/Barretenberg compatibility, DKG and threshold structure, proof binding and domain separation, and E3 program input rules. @@ -440,13 +440,14 @@ every section. (no BFV decoding/Poseidon2 in Solidity); C3/C6 commitments are checked against their ciphertext witnesses. — INDEX IF-004 - **Ciphertext-duty proof (Zenith #15):** each E3 snapshots the protocol verifier for its encryption - scheme at request time. Before `CiphertextReady`, this verifier checks a RISC Zero receipt that + scheme at request time. Before `CiphertextReady`, this verifier checks a zkVM receipt that binds the chain, Interfold address, E3 ID, scheme ID, BFV parameter hash, committee public key, output hash, and SAFE commitment. The E3 program verifies application rules separately and cannot create a decryption duty by itself. — `flow-trace/04`; INDEX Z-15 - **The compute path carries no external audit.** Neither Zenith protocol audit (2026-08-17, six - Solidity files; 2026-09-08, a scoped review of 14 Solidity files) covered Rust, the RISC Zero - guest, `crates/compute-provider`, `crates/zk-helpers`, or `Risc0BfvCiphertextVerifier.sol`. Treat + Solidity files; 2026-09-08, a scoped review of 14 Solidity files) covered Rust, the OpenVM + guest and prover, `crates/compute-provider`, `crates/zk-helpers`, or the OpenVM receipt + verifiers (`OpenVmBfvCiphertextVerifier.sol`, `OpenVmReceiptVerifier.sol`). Treat changes there as unaudited. — `packages/interfold-contracts/audits/README.md` - **A Secure Process derives its input root; it never receives it.** `ComputeInput` holds `fhe_inputs` and per-input `published` data, never a root, and `ComputeInput::process` derives one @@ -458,7 +459,7 @@ every section. publish a tally over ciphertexts that were never submitted. `MerkleTreeBuilder::with_leaf_hashes` is `#[cfg(test)]` to keep it out of that path. — `flow-trace/04` - **Every E3 program must compare the proof's input root against its own root.** - `Risc0BfvCiphertextVerifier` authenticates the receipt's `inputRoot` but compares it with nothing. + `OpenVmBfvCiphertextVerifier` authenticates the receipt's `inputRoot` but compares it with nothing. A program that skips the comparison accepts a result computed over any input set. — `flow-trace/04` - **A Secure Process derives its leaves; it never receives them, and never drops one.** diff --git a/agent/invariants/04_BUILD_CONFIG.md b/agent/invariants/04_BUILD_CONFIG.md index 5a1cd8c46e..3a08680dd1 100644 --- a/agent/invariants/04_BUILD_CONFIG.md +++ b/agent/invariants/04_BUILD_CONFIG.md @@ -12,9 +12,8 @@ every section. `scripts/check-committee.sh` runs in pre-push and in the Agent Harness CI workflow. - **Never hand-edit generated files:** parity matrices, `configs/default/mod.nr`, `configs/committee/active.nr`, the generated C1/C2 bounds, the generated constants in `utils.ts`, - `ActiveCryptoConfig.sol`, verifier contracts (`generate-verifiers.ts` output), - `crates/support/contracts/ImageID.sol`, and the ignored local files `.active-preset.json` and - `crates/support/tests/Elf.sol`. + `ActiveCryptoConfig.sol`, verifier contracts (`generate-verifiers.ts` output), the ignored local + file `.active-preset.json`, and prepared OpenVM identity artifacts. - **Generated verifiers must match the built VKs.** When a pushed branch changes a path in `.github/filters/circuits.yml`, pre-push checks `insecure-512` with the committee in the local `.active-preset.json` (default `minimum`). The check reads the checked-out tree, so the hook stops @@ -51,15 +50,15 @@ every section. ciphernode, and DAppNode copies the checked ciphernode image. CI generates a manifest for exactly the staged fixture before packaging and hashing it. — `02_CRYPTO_CIRCUITS.md` §Noir / Barretenberg compatibility -- **`Elf.sol` is never committed.** `crates/support/methods/build.rs` writes it with a machine-local - guest ELF path, so it is generated per checkout and `.gitignore`d. +- **Deployment-local OpenVM artifacts are never committed.** Keep executable files, proving keys, + proofs, inputs, worker configurations, and benchmark reports under `target/` or outside source. - **A release publishes a complete provenance manifest** — `pnpm provenance:manifest`. It ties - source commit, lockfile digests, pinned revisions, RISC Zero version, builder image tag **and - digest** (the builder tag is mutable and `RISC0_DOCKER_CONTAINER_TAG` overrides it), guest ELF - SHA-256, image ID, and the deployed verifier to one record. The generator reports - `complete: false` with the unresolved fields rather than emitting a partial record that reads as - verified. The ELF SHA-256 is **not** the image ID: SHA-256 checks binary integrity, the image ID - is computed from the loaded memory image. Procedure: + source commit, lockfile and artifact digests, OpenVM application commitments, worker identity + validation, and the deployed protocol, receipt, and Halo2 verifiers to one record. The generator + reports `complete: false` with the unresolved fields rather than emitting a partial record that + reads as verified. An artifact SHA-256 is **not** an application commitment or receipt identity. + A complete record does not establish source reproducibility; retain independent rebuild evidence. + Procedure: `docs/pages/build/e3-program/verify-compute-provider.mdx`. **Gap:** the release workflow does not generate or attach this manifest (`.github/workflows/releases.yml`); a maintainer runs `pnpm provenance:manifest` by hand. @@ -75,7 +74,7 @@ every section. `BondingRegistry`, `CiphernodeRegistryOwnable`, and the canonical `insecure-512/minimum` aggregator verifiers. Every deployed verifier variant must fit, but CI does not measure the other variants. — `scripts/checkContractSize.ts`; INDEX concern #22 -- BFV circuit-verifier and RISC Zero receipt-verifier constructors require deployed verifier +- BFV circuit-verifier and OpenVM receipt-verifier constructors require deployed verifier contracts. BFV circuit wrappers also require nonzero recursive VK hashes. — INDEX concerns #21, Z-15 - CLI secrets enter through **stdin or hidden prompts**, never argv or the environment. Wallet keys diff --git a/crates/bfv-client/Cargo.toml b/crates/bfv-client/Cargo.toml index c55329d7b5..0ef6c8968d 100644 --- a/crates/bfv-client/Cargo.toml +++ b/crates/bfv-client/Cargo.toml @@ -15,3 +15,6 @@ fhe-traits.workspace = true rand.workspace = true thiserror = { workspace = true } e3-polynomial = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(crisp_fhe_optimized)'] } diff --git a/crates/bfv-client/src/client.rs b/crates/bfv-client/src/client.rs index efe0cfb31b..586b5433f9 100644 --- a/crates/bfv-client/src/client.rs +++ b/crates/bfv-client/src/client.rs @@ -239,6 +239,26 @@ pub fn compute_ct_commitment_with_params( ) -> Result<[u8; 32]> { use e3_zk_helpers::circuits::threshold::user_data_encryption::utils::compute_ciphertext_commitment; + #[cfg(crisp_fhe_optimized)] + if let Some(components) = Ciphertext::power_basis_from_bytes_if_canonical(ct, params)? { + use e3_zk_helpers::{commitments, utils::compute_modulus_bit}; + if let Some(commitment) = commitments::compute_ciphertext_commitment_from_power_basis( + &components[0], + &components[1], + params.moduli(), + compute_modulus_bit(params), + ) { + let bytes = commitment.to_bytes_be().1; + anyhow::ensure!( + bytes.len() <= 32, + "The ciphertext commitment exceeds 32 bytes" + ); + let mut result = [0; 32]; + result[32 - bytes.len()..].copy_from_slice(&bytes); + return Ok(result); + } + } + let ct = Ciphertext::from_bytes(ct, params) .map_err(|e| anyhow!("Error deserializing ciphertext: {}", e))?; diff --git a/crates/cli/src/program.rs b/crates/cli/src/program.rs index 6cc9bfe009..4c7ac95bee 100644 --- a/crates/cli/src/program.rs +++ b/crates/cli/src/program.rs @@ -25,12 +25,6 @@ pub enum ProgramCommands { dev: Option, }, - /// Get a shell into the docker environment that the program runs in - Shell, - - /// Upload the compiled program to Pinata IPFS - Upload, - /// Commands to manage the program compilation cache Cache { #[command(subcommand)] @@ -52,10 +46,6 @@ pub async fn execute(command: ProgramCommands, config: &AppConfig) -> Result<()> ProgramCommands::Compile { dev } => { e3_support_scripts::program_compile(config.program().clone(), dev).await? } - ProgramCommands::Shell => e3_support_scripts::program_shell().await?, - ProgramCommands::Upload => { - e3_support_scripts::program_upload(config.program().clone(), None).await? - } ProgramCommands::Cache { command } => match command { ProgramCacheCommands::Purge => e3_support_scripts::program_cache_purge().await?, }, diff --git a/crates/compute-provider/Cargo.toml b/crates/compute-provider/Cargo.toml index 91c4e575c5..eb536b5604 100644 --- a/crates/compute-provider/Cargo.toml +++ b/crates/compute-provider/Cargo.toml @@ -23,12 +23,15 @@ fhe = { workspace = true } e3-fhe-params = { workspace = true, features = ["abi-encoding"] } thiserror = { workspace = true } rayon = { version = "=1.10.0", optional = true } +openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } [features] default = [] # Computes the per-input ciphertext commitments on a thread pool. Off by default because the -# zkVM guest is single threaded: it takes this crate by git revision and must not pull in rayon. +# zkVM guest is single threaded and must not pull in rayon. parallel = ["dep:rayon"] +# Uses the OpenVM Keccak-256 and SHA-256 instructions inside the OpenVM guest. +openvm-hashes = ["dep:openvm-keccak256"] [dev-dependencies] fhe = { workspace = true } diff --git a/crates/compute-provider/Readme.md b/crates/compute-provider/Readme.md index 3d7740c6d9..215722a163 100644 --- a/crates/compute-provider/Readme.md +++ b/crates/compute-provider/Readme.md @@ -125,10 +125,10 @@ impl ComputeProvider for MyProvider { `prove` receives the policy rather than choosing one. A prover that picked its own would select a different input set from the one `start` returned the ciphertext for. -The repository's RISC Zero and Boundless providers live in `e3-support-host`. That crate is in a -separate workspace, so the dependency above does not pull it in. Inside an Interfold checkout, its -`run_risc0_compute` and `run_compute` entry points wrap the two backends, and -`crates/support/host/src/lib.rs` is the reference implementation to read. +The OpenVM host lives in `e3-support-host`, in a separate workspace. Its `run_compute` function +derives the native ciphertext and journal, then calls a separate OpenVM worker. The worker must +return a verified EVM receipt. Read `crates/support/host/src/lib.rs` and +`crates/support/openvm/README.md` for the implementation and configuration. ## Configuration diff --git a/crates/compute-provider/src/compute_input.rs b/crates/compute-provider/src/compute_input.rs index 2d9975a679..6154547782 100644 --- a/crates/compute-provider/src/compute_input.rs +++ b/crates/compute-provider/src/compute_input.rs @@ -5,6 +5,7 @@ // or FITNESS FOR A PARTICULAR PURPOSE. use crate::ciphertext_output::ComputeResult; +use crate::hashing::keccak256; use crate::merkle_tree_builder::{Batching, MerkleTreeBuilder}; use crate::policy::InputPolicy; #[cfg(test)] @@ -12,7 +13,6 @@ use e3_bfv_client::client::compute_ct_commitment; use e3_bfv_client::client::compute_ct_commitment_with_params; use e3_fhe_params::decode_bfv_params_arc; use fhe::bfv::BfvParameters; -use sha3::{Digest, Keccak256}; use std::sync::Arc; pub type FHEProcessor = for<'a> fn(&FHEProcessorInput<'a>) -> Vec; @@ -126,8 +126,23 @@ impl ComputeInput { policy: InputPolicy, batching: Batching, ) -> Result<(ComputeResult, Vec), ComputeError> { + self.run_observed(fhe_processor, policy, batching, |_, _| {}) + } + + /// As [`Self::run_batched`], and reports phase boundaries without exposing or changing the + /// computed values. The observer receives `true` at the start and `false` at the end of each + /// phase. A failed phase does not emit an end event. + pub fn run_observed( + &self, + fhe_processor: FHEProcessor, + policy: InputPolicy, + batching: Batching, + mut observe: impl FnMut(&'static str, bool), + ) -> Result<(ComputeResult, Vec), ComputeError> { + observe("params", true); let params = decode_bfv_params_arc(&self.fhe_inputs.params) .map_err(|e| ComputeError::DecodeParams(e.to_string()))?; + observe("params", false); if !self.published.is_empty() && self.published.len() != self.fhe_inputs.ciphertexts.len() { return Err(ComputeError::MerkleTree(format!( @@ -137,6 +152,7 @@ impl ComputeInput { ))); } + observe("input_commitments_and_selection", true); let mut tree_builder = MerkleTreeBuilder::new(self.fhe_inputs.ciphertexts.len()); let selected = tree_builder.compute_leaf_hashes_batched( &self.fhe_inputs, @@ -145,25 +161,36 @@ impl ComputeInput { policy, batching, )?; + observe("input_commitments_and_selection", false); + observe("input_tree", true); let merkle_root = tree_builder .build_tree() .map_err(|e| ComputeError::MerkleTree(e.to_string()))? .root() .ok_or_else(|| ComputeError::MerkleTree("the tree has no root".into()))?; + observe("input_tree", false); // The processor sees only what the policy selected. Both the root above and this set are // functions of values the root binds, so any prover over the same published inputs reaches // the same result. + observe("fhe_processor", true); let processed_ciphertext = (fhe_processor)(&FHEProcessorInput { ciphertexts: &selected, params: ¶ms, }); - let processed_hash = Keccak256::digest(&processed_ciphertext).to_vec(); + observe("fhe_processor", false); + observe("output_hash", true); + let processed_hash = keccak256(&processed_ciphertext).to_vec(); + observe("output_hash", false); + observe("output_commitment", true); let ciphertext_commitment = compute_ct_commitment_with_params(&processed_ciphertext, ¶ms) .map_err(|e| ComputeError::OutputCommitment(e.to_string()))? .to_vec(); - let params_hash = Keccak256::digest(&self.fhe_inputs.params).to_vec(); + observe("output_commitment", false); + observe("params_hash", true); + let params_hash = keccak256(&self.fhe_inputs.params).to_vec(); + observe("params_hash", false); Ok(( ComputeResult { @@ -187,6 +214,7 @@ mod tests { use fhe_traits::{FheEncoder, FheEncrypter, Serialize as FheSerialize}; use rand::SeedableRng; use rand_chacha::ChaCha8Rng; + use sha3::{Digest, Keccak256}; fn sum_processor(inputs: &FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(inputs.params); for (bytes, _) in inputs.ciphertexts { diff --git a/crates/compute-provider/src/hashing.rs b/crates/compute-provider/src/hashing.rs new file mode 100644 index 0000000000..13651c7ac1 --- /dev/null +++ b/crates/compute-provider/src/hashing.rs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +/// Computes the protocol Keccak-256 digest without changing its input encoding. +pub fn keccak256(input: &[u8]) -> [u8; 32] { + #[cfg(feature = "openvm-hashes")] + { + openvm_keccak256::keccak256(input) + } + #[cfg(not(feature = "openvm-hashes"))] + { + use sha3::{Digest, Keccak256}; + Keccak256::digest(input).into() + } +} + +#[cfg(test)] +mod tests { + use super::keccak256; + use sha3::{Digest, Keccak256}; + + #[test] + fn keccak_matches_reference_at_block_boundaries_and_unaligned_offsets() { + for len in [0, 1, 31, 32, 63, 64, 135, 136, 137, 271, 272, 273, 356_469] { + let bytes: Vec = (0..len + 4).map(|index| (index * 71 + 13) as u8).collect(); + for offset in 0..4 { + let input = &bytes[offset..offset + len]; + let expected: [u8; 32] = Keccak256::digest(input).into(); + assert_eq!(keccak256(input), expected, "length {len}, offset {offset}"); + } + } + } +} diff --git a/crates/compute-provider/src/lib.rs b/crates/compute-provider/src/lib.rs index 27ef0a5d0e..72c3dd9437 100644 --- a/crates/compute-provider/src/lib.rs +++ b/crates/compute-provider/src/lib.rs @@ -7,6 +7,7 @@ mod ciphertext_output; mod compute_input; mod compute_manager; +pub mod hashing; mod merkle_tree_builder; pub mod policy; diff --git a/crates/config/src/app_config.rs b/crates/config/src/app_config.rs index dd87d62a6f..2dc55d4f2e 100644 --- a/crates/config/src/app_config.rs +++ b/crates/config/src/app_config.rs @@ -617,7 +617,7 @@ pub fn combine_unique(a: &[T], b: &[T]) - #[cfg(test)] mod tests { use super::*; - use crate::program_config::Risc0Config; + use crate::program_config::OpenVmConfig; use crate::rpc::RpcAuth; use figment::Jail; @@ -647,8 +647,10 @@ node: quic_port: 1234 program: - risc0: - risc0_dev_mode: 0 + openvm: + repository: "/deployment/source" + prover_bin: "/deployment/bin/interfold-openvm-prover" + prover_config: "/deployment/prover.json" nodes: ag: @@ -679,10 +681,11 @@ nodes: ); assert_eq!(config.quic_port(), 1234); assert_eq!( - config.program().risc0(), - Some(&Risc0Config { - risc0_dev_mode: 0, - boundless: None, + config.program().openvm(), + Some(&OpenVmConfig { + repository: PathBuf::from("/deployment/source"), + prover_bin: PathBuf::from("/deployment/bin/interfold-openvm-prover"), + prover_config: PathBuf::from("/deployment/prover.json"), }) ); assert!(config.peers().is_empty()); diff --git a/crates/config/src/program_config.rs b/crates/config/src/program_config.rs index 7d98502eb7..e6779aab57 100644 --- a/crates/config/src/program_config.rs +++ b/crates/config/src/program_config.rs @@ -4,7 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -//! Program execution configuration (RISC Zero / Boundless). +//! OpenVM program execution configuration. //! //! Extracted from [`AppConfig`] — these types configure external program //! execution, not the ciphernode itself. @@ -12,76 +12,23 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct BoundlessConfig { - pub rpc_url: String, - pub private_key: String, - #[serde(default)] - pub pinata_jwt: Option, - /// Public gateway base URL used in Boundless program and input references. - /// - /// Use a dedicated gateway for production. The shared Pinata gateway can accept a HEAD - /// request and then rate-limit the full object download that a prover needs. - #[serde(default)] - pub ipfs_gateway_url: Option, - #[serde(default)] - pub program_url: Option, - #[serde(default = "default_true")] - pub onchain: bool, - // --- Offer parameters (all optional; the support host supplies the defaults) --- - /// Minimum price in ETH (default: 0.00005). - #[serde(default)] - pub min_price_eth: Option, - /// Maximum price in ETH (default: 0.004). - #[serde(default)] - pub max_price_eth: Option, - /// Total timeout in seconds (default: 28800 = 8 hours). - #[serde(default)] - pub timeout_secs: Option, - /// Lock timeout in seconds (default: 14400 = 4 hours). - #[serde(default)] - pub lock_timeout_secs: Option, - /// Ramp-up period in seconds (default: 7200 = 2 hours). - #[serde(default)] - pub ramp_up_secs: Option, - /// Lock collateral in ZKC (default: 100.0). - #[serde(default)] - pub lock_collateral_zkc: Option, -} - -fn default_true() -> bool { - true -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct Risc0Config { - #[serde(default = "default_risc0_dev_mode")] - pub risc0_dev_mode: u8, - #[serde(default)] - pub boundless: Option, -} - -fn default_risc0_dev_mode() -> u8 { - 1 -} - -impl Default for Risc0Config { - fn default() -> Self { - Risc0Config { - risc0_dev_mode: 1, - boundless: None, - } - } +#[serde(deny_unknown_fields)] +pub struct OpenVmConfig { + pub repository: std::path::PathBuf, + pub prover_bin: std::path::PathBuf, + pub prover_config: std::path::PathBuf, } #[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] pub struct ProgramConfig { - risc0: Option, + openvm: Option, dev: Option, } impl ProgramConfig { - pub fn risc0(&self) -> Option<&Risc0Config> { - self.risc0.as_ref() + pub fn openvm(&self) -> Option<&OpenVmConfig> { + self.openvm.as_ref() } pub fn dev(&self) -> bool { @@ -94,27 +41,34 @@ mod tests { use super::ProgramConfig; #[test] - fn deserializes_dedicated_ipfs_gateway() { + fn deserializes_openvm_worker_configuration() { let config: ProgramConfig = serde_yaml::from_str( r#" -risc0: - risc0_dev_mode: 0 - boundless: - rpc_url: "https://base.example" - private_key: "demo" - pinata_jwt: "demo" - ipfs_gateway_url: "https://dedicated.example" +openvm: + repository: "/deployment/source" + prover_bin: "/deployment/bin/interfold-openvm-prover" + prover_config: "/deployment/prover.json" "#, ) .expect("program config must deserialize"); - let boundless = config - .risc0() - .and_then(|risc0| risc0.boundless.as_ref()) - .expect("Boundless config must be present"); + let openvm = config.openvm().expect("OpenVM config must be present"); assert_eq!( - boundless.ipfs_gateway_url.as_deref(), - Some("https://dedicated.example") + openvm.prover_bin, + std::path::PathBuf::from("/deployment/bin/interfold-openvm-prover") ); + assert!(!config.dev()); + } + + #[test] + fn rejects_unknown_backend_configuration() { + assert!(serde_yaml::from_str::("unknown_backend: {}").is_err()); + } + + #[test] + fn development_execution_requires_explicit_selection() { + assert!(!ProgramConfig::default().dev()); + let config: ProgramConfig = serde_yaml::from_str("dev: true").unwrap(); + assert!(config.dev()); } } diff --git a/crates/init/src/container_permissions.rs b/crates/init/src/container_permissions.rs deleted file mode 100644 index 9c68cfca39..0000000000 --- a/crates/init/src/container_permissions.rs +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use std::path::{Path, PathBuf}; - -/// Permission mode for the directories that the support container writes to. -/// -/// The capital `X` adds the execute bit to directories only. Plain files do not -/// get the execute bit. A directory needs it to stay traversable. Solidity and -/// TypeScript sources do not need it. -pub const CONTAINER_WRITABLE_MODE: &str = "a+rwX"; - -/// UID of `devuser` in the support container image. -/// -/// `crates/support/Dockerfile` sets this UID at build time. The CLI pulls the -/// image prebuilt, so a user cannot rebuild it with a different UID. -const SUPPORT_CONTAINER_UID: u32 = 1000; - -/// Reports whether the project files need wider permissions for the container. -/// -/// Only Linux keeps host ownership on a bind mount. If the owner is already the -/// container user, the default modes are sufficient. -pub async fn needs_permission_widening(cwd: &Path) -> anyhow::Result { - use std::os::unix::fs::MetadataExt; - let owner_uid = tokio::fs::metadata(cwd).await?.uid(); - Ok(widening_needed(cfg!(target_os = "linux"), owner_uid)) -} - -fn widening_needed(host_uids_reach_container: bool, owner_uid: u32) -> bool { - host_uids_reach_container && owner_uid != SUPPORT_CONTAINER_UID -} - -/// Lists the directories that the support container mounts read-write. -/// -/// The RISC Zero build script in `crates/support/methods/build.rs` writes -/// `ImageID.sol` to `../contracts` and `Elf.sol` to `../tests`, both relative -/// to `/app`. `ctl/container` maps these two paths to -/// `.interfold/generated/contracts` and `tests` on the host. -pub fn container_writable_paths(cwd: &Path) -> Vec { - vec![ - cwd.join(".interfold").join("generated").join("contracts"), - cwd.join("tests"), - ] -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::Path; - - #[test] - fn writable_paths_are_the_directories_the_container_mounts() { - let cwd = Path::new("/proj"); - let paths = container_writable_paths(cwd); - - assert!(paths.contains(&cwd.join(".interfold/generated/contracts"))); - assert!(paths.contains(&cwd.join("tests"))); - } - - #[test] - fn the_projects_own_contracts_folder_is_not_widened() { - let cwd = Path::new("/proj"); - let paths = container_writable_paths(cwd); - - // `contracts/` holds the project's own Solidity sources. Neither - // `ctl/container` nor `support/scripts/dev.sh` mounts it into the - // container. Wider permissions there give access that nothing needs. - assert!(!paths.contains(&cwd.join("contracts"))); - } - - #[test] - fn no_widening_when_the_container_user_already_owns_the_files() { - assert!(!widening_needed(true, SUPPORT_CONTAINER_UID)); - } - - #[test] - fn widening_when_the_owner_differs_from_the_container_user() { - assert!(widening_needed(true, SUPPORT_CONTAINER_UID + 1)); - } - - #[test] - fn no_widening_when_the_platform_maps_ownership() { - // Docker Desktop translates ownership in its file-sharing layer. A - // different UID never reaches the container. - assert!(!widening_needed(false, SUPPORT_CONTAINER_UID + 1)); - } - - #[tokio::test] - async fn writable_mode_keeps_directories_traversable() -> anyhow::Result<()> { - let root = tempfile::tempdir()?; - let nested = root.path().join("nested"); - tokio::fs::create_dir(&nested).await?; - - crate::file_utils::chmod_recursive(root.path(), CONTAINER_WRITABLE_MODE).await?; - - // Without the execute bit, no process can enter a directory. The - // container cannot then reach the files inside it. - assert_eq!(mode_of(&nested).await? & 0o111, 0o111); - assert_eq!(mode_of(&nested).await? & 0o222, 0o222); - Ok(()) - } - - #[tokio::test] - async fn writable_mode_does_not_mark_sources_executable() -> anyhow::Result<()> { - let root = tempfile::tempdir()?; - let source = root.path().join("MyProgram.sol"); - tokio::fs::write(&source, "// contract").await?; - - crate::file_utils::chmod_recursive(root.path(), CONTAINER_WRITABLE_MODE).await?; - - // Solidity sources are not programs. `777` set the execute bit on - // every source file. The template still carries `100755` blobs from - // an earlier run. - assert_eq!(mode_of(&source).await? & 0o111, 0); - assert_eq!(mode_of(&source).await? & 0o222, 0o222); - Ok(()) - } - - async fn mode_of(path: &Path) -> anyhow::Result { - use std::os::unix::fs::PermissionsExt; - Ok(tokio::fs::metadata(path).await?.permissions().mode() & 0o777) - } -} diff --git a/crates/init/src/file_utils.rs b/crates/init/src/file_utils.rs index 5031e515f8..5a895a4c59 100644 --- a/crates/init/src/file_utils.rs +++ b/crates/init/src/file_utils.rs @@ -44,22 +44,6 @@ pub async fn delete_path>(path: P) -> Result<()> { Ok(()) } -pub async fn chmod_recursive>(path: P, mode: &str) -> Result<()> { - let path = path.as_ref(); - let status = Command::new("chmod") - .arg("-R") - .arg(mode) - .arg(path) - .status() - .await?; - - if !status.success() { - bail!("❌ Failed to set permissions on '{}'", path.display()); - } - - Ok(()) -} - pub async fn move_file, Q: AsRef>(src: P, dst: Q) -> Result<()> { Command::new("mv") .arg(src.as_ref()) @@ -107,20 +91,3 @@ pub async fn remove_dir_except(dir: &Path, keep: &[&str]) -> Result<()> { } Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn chmod_recursive_reports_a_failed_run() -> Result<()> { - let root = tempfile::tempdir()?; - - // A caller acts on the result. A `chmod` that runs and then fails must - // not look like a success. - let result = chmod_recursive(root.path().join("does-not-exist"), "a+rwX").await; - - assert!(result.is_err()); - Ok(()) - } -} diff --git a/crates/init/src/git.rs b/crates/init/src/git.rs index 206572a4fb..f9aa9d5a37 100644 --- a/crates/init/src/git.rs +++ b/crates/init/src/git.rs @@ -104,36 +104,6 @@ pub async fn commit(path: impl AsRef, message: &str, verbose: bool) -> Res Ok(()) } -pub async fn add_submodule( - repo_path: impl AsRef, - submodule_url: &str, - submodule_path: &str, - verbose: bool, -) -> Result<()> { - let repo_path = repo_path.as_ref(); - - let mut args = vec!["submodule", "add", submodule_url, submodule_path]; - if !verbose { - args.insert(2, "--quiet"); - } - - Command::new("git") - .args(&args) - .current_dir(repo_path) - .output() - .await - .with_context(|| { - format!( - "Failed to add git submodule '{}' at '{}' in directory: {}", - submodule_url, - submodule_path, - repo_path.display() - ) - })?; - - Ok(()) -} - pub async fn get_commit_hash(path: impl AsRef) -> Result { let path = path.as_ref(); diff --git a/crates/init/src/lib.rs b/crates/init/src/lib.rs index 57caba0e56..31fc4fd947 100644 --- a/crates/init/src/lib.rs +++ b/crates/init/src/lib.rs @@ -4,7 +4,6 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -mod container_permissions; mod copy; mod file_utils; mod git; @@ -13,15 +12,9 @@ mod package_json; mod pkgman; use anyhow::Result; -use container_permissions::{ - container_writable_paths, needs_permission_widening, CONTAINER_WRITABLE_MODE, -}; use copy::Filter; -use file_utils::{ - chmod_recursive, delete_path, move_file, remove_all_files_in_dir, remove_dir_except, -}; +use file_utils::{delete_path, move_file, remove_all_files_in_dir, remove_dir_except}; use git::parse_git_url; -use package_json::DependencyType; use pkgman::PkgMan; use std::path::PathBuf; use std::process::exit; @@ -170,14 +163,7 @@ async fn install_interfold( .await?; spinner - .run("Setting up support folders ctl and dev", || async { - copy::copy_with_filters( - &PathBuf::from(TEMP_DIR).join("crates/support-scripts/ctl"), - &cwd.join(".interfold/support/ctl"), - &[], - ) - .await?; - + .run("Setting up the development runner", || async { copy::copy_with_filters( &PathBuf::from(TEMP_DIR).join("crates/support-scripts/dev"), &cwd.join(".interfold/support/dev"), @@ -217,58 +203,13 @@ async fn install_interfold( spinner.complete_task("Support folders set up\n"); - // The support container runs as a fixed user. The directories that it - // mounts read-write need permissions that let this user write to them. - if needs_permission_widening(cwd).await? { - spinner.update("Restoring permissions...".to_string()).await; - - for path in container_writable_paths(cwd) { - let message = format!( - "Setting {} permissions to {}", - path.display(), - CONTAINER_WRITABLE_MODE - ); - spinner - .run(message, || async { - chmod_recursive(&path, CONTAINER_WRITABLE_MODE).await - }) - .await?; - } - - spinner.complete_task("Permissions restored\n"); - } - - spinner.update("Setting up submodules...").await; + spinner.update("Setting up the project repository...").await; spinner .run("Init git repo", || async { git::init(&cwd, verbose).await }) .await?; - spinner - .run("Adding @risc0/ethereum submodule", || async { - git::add_submodule( - &cwd, - "https://github.com/gnosisguild/risc0-ethereum", - "lib/risc0-ethereum", - verbose, - ) - .await - }) - .await?; - - spinner - .run("Ensuring @risc0/ethereum is in package.json", || async { - package_json::add_package_to_json( - &cwd.join("package.json"), - "@risc0/ethereum", - "file:lib/risc0-ethereum", - DependencyType::DevDependencies, - ) - .await - }) - .await?; - - spinner.complete_task("Submodules set up\n"); + spinner.complete_task("Project repository set up\n"); if skip_install { spinner.complete_task("Package installation skipped\n"); diff --git a/crates/init/src/package_json.rs b/crates/init/src/package_json.rs index 8b920956fd..561309f94a 100644 --- a/crates/init/src/package_json.rs +++ b/crates/init/src/package_json.rs @@ -7,27 +7,9 @@ use std::path::PathBuf; use anyhow::Result; -use serde_json::{Map, Value}; +use serde_json::Value; use tokio::fs; -#[allow(dead_code)] -#[derive(Debug, Clone)] -pub enum DependencyType { - Dependencies, - DevDependencies, - PeerDependencies, -} - -impl DependencyType { - fn as_key(&self) -> &'static str { - match self { - DependencyType::Dependencies => "dependencies", - DependencyType::DevDependencies => "devDependencies", - DependencyType::PeerDependencies => "peerDependencies", - } - } -} - pub async fn get_version_from_package_json(file_path: &PathBuf) -> Result { let content = fs::read_to_string(file_path).await?; let json: Value = serde_json::from_str(&content)?; @@ -37,57 +19,3 @@ pub async fn get_version_from_package_json(file_path: &PathBuf) -> Result Result<()> { - let dep_key = dep_type.as_key(); - let content = fs::read_to_string(file_path).await?; - - let mut json: Value = serde_json::from_str(&content)?; - - let obj = json - .as_object_mut() - .ok_or_else(|| anyhow::anyhow!("package.json root is not an object"))?; - - let deps = obj - .entry(dep_key) - .or_insert_with(|| Value::Object(Map::new())) - .as_object_mut() - .ok_or_else(|| anyhow::anyhow!("{} is not an object", dep_key))?; - - deps.insert(package_name.to_string(), Value::String(version.to_string())); - - let formatted_json = serde_json::to_string_pretty(&json)?; - fs::write(file_path, formatted_json).await?; - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn add_dev_dependency_keeps_existing_fields() { - let directory = tempfile::tempdir().unwrap(); - let path = directory.path().join("package.json"); - fs::write(&path, r#"{"version":"1.2.3","devDependencies":{"a":"1"}}"#) - .await - .unwrap(); - - add_package_to_json(&path, "b", "2", DependencyType::DevDependencies) - .await - .unwrap(); - - let saved: Value = serde_json::from_str(&fs::read_to_string(&path).await.unwrap()).unwrap(); - assert_eq!( - saved["devDependencies"], - serde_json::json!({"a": "1", "b": "2"}) - ); - assert_eq!(get_version_from_package_json(&path).await.unwrap(), "1.2.3"); - } -} diff --git a/crates/safe/Cargo.toml b/crates/safe/Cargo.toml index 0ad791ee12..10ceb1698e 100644 --- a/crates/safe/Cargo.toml +++ b/crates/safe/Cargo.toml @@ -6,15 +6,23 @@ license.workspace = true description = "E3 - Interfold SAFE" repository.workspace = true +[features] +openvm = ["dep:openvm", "dep:openvm-algebra-guest", "dep:serde", "dep:num-bigint"] +phase-trace = ["openvm"] + [dependencies] sha3 = "0.10.8" ark-ff = { workspace = true } ark-bn254 = { workspace = true } taceo-poseidon2 = { version = "0.2", features = ["bn254", "t4"] } hex = { workspace = true } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } +openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } +serde = { workspace = true, optional = true } +num-bigint = { version = "=0.4.6", optional = true } -[target.'cfg(all(target_os = "zkvm", target_arch = "riscv32"))'.dependencies] -risc0-bigint2 = "=1.4.7" +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(crisp_openvm)'] } [dev-dependencies] rand = { workspace = true } diff --git a/crates/safe/src/lib.rs b/crates/safe/src/lib.rs index 5eabd7bc1c..542ace352c 100644 --- a/crates/safe/src/lib.rs +++ b/crates/safe/src/lib.rs @@ -24,6 +24,8 @@ use ark_bn254::Fr; use ark_ff::Zero; use sha3::{Digest, Keccak256}; +#[cfg(all(crisp_openvm, not(feature = "openvm")))] +compile_error!("The OpenVM build requires the e3-safe/openvm feature"); #[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] use taceo_poseidon2::bn254::t4::permutation as poseidon2_permutation; @@ -99,6 +101,8 @@ impl SafeSponge { /// # Returns /// A new `SafeSponge` instance with initialized state pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge { + #[cfg(all(feature = "phase-trace", target_os = "zkvm"))] + openvm::io::println(format!("phase:safe:{io_pattern:?}:start")); // Compute tag from IO pattern and domain separator (spec 2.3). let tag = compute_tag(io_pattern, domain_separator); @@ -230,6 +234,8 @@ impl SafeSponge { self.absorb_pos = 0; self.squeeze_pos = 0; self.io_count = 0; + #[cfg(all(feature = "phase-trace", target_os = "zkvm"))] + openvm::io::println("phase:safe:end"); } /// Permute the state using Poseidon2 (following spec 2.4). diff --git a/crates/safe/src/poseidon2_accel.rs b/crates/safe/src/poseidon2_accel.rs index 9b964eabd1..b9e8f1caac 100644 --- a/crates/safe/src/poseidon2_accel.rs +++ b/crates/safe/src/poseidon2_accel.rs @@ -4,25 +4,105 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -//! RISC Zero-accelerated implementation of the exact BN254 Poseidon2 permutation used by SAFE. +//! Accelerated implementation of the exact BN254 Poseidon2 permutation used by SAFE. use ark_bn254::Fr; -use ark_ff::{BigInt, PrimeField}; +use ark_ff::BigInt; +#[cfg(not(feature = "openvm"))] +use ark_ff::PrimeField; + +#[cfg(feature = "openvm")] +extern crate alloc; + +#[cfg(feature = "openvm")] +use openvm_algebra_guest::{moduli_macros::moduli_declare, IntMod}; + +#[cfg(feature = "openvm")] +moduli_declare! { + Bn254Scalar { modulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617" } +} const WIDTH: usize = 4; +#[cfg(not(feature = "openvm"))] const MODULUS: [u32; 8] = [ 0xf0000001, 0x43e1f593, 0x79b97091, 0x2833e848, 0x8181585d, 0xb85045b6, 0xe131a029, 0x30644e72, ]; +#[cfg(feature = "openvm")] +impl Copy for Bn254Scalar {} + +#[cfg(feature = "openvm")] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct FastField(Bn254Scalar); +#[cfg(not(feature = "openvm"))] #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct FastField([u32; 8]); impl FastField { - const ZERO: Self = Self([0; 8]); + #[cfg(any(not(feature = "openvm"), test))] + const ZERO: Self = Self::new([0; 8]); + + #[cfg(feature = "openvm")] + const MONTGOMERY_R: Self = Self::new([ + Fr::R.0[0] as u32, + (Fr::R.0[0] >> 32) as u32, + Fr::R.0[1] as u32, + (Fr::R.0[1] >> 32) as u32, + Fr::R.0[2] as u32, + (Fr::R.0[2] >> 32) as u32, + Fr::R.0[3] as u32, + (Fr::R.0[3] >> 32) as u32, + ]); + + #[cfg(feature = "openvm")] + const MONTGOMERY_R_INVERSE: Self = Self::new([ + 0x6db1194e, 0xdc5ba005, 0xe111ec87, 0x090ef5a9, 0xaeb85d5d, 0xc8260de4, 0x82c5551c, + 0x15ebf951, + ]); + + const fn new(words: [u32; 8]) -> Self { + #[cfg(not(feature = "openvm"))] + { + Self(words) + } + #[cfg(feature = "openvm")] + { + let mut bytes = [0; 32]; + let mut index = 0; + while index < 8 { + let word = words[index].to_le_bytes(); + let mut byte = 0; + while byte < 4 { + bytes[index * 4 + byte] = word[byte]; + byte += 1; + } + index += 1; + } + Self(Bn254Scalar::from_const_bytes(bytes)) + } + } + + fn words(self) -> [u32; 8] { + #[cfg(not(feature = "openvm"))] + { + self.0 + } + #[cfg(feature = "openvm")] + { + let mut words = [0; 8]; + for (word, bytes) in words.iter_mut().zip(self.0.as_le_bytes().chunks_exact(4)) { + *word = u32::from_le_bytes(bytes.try_into().unwrap()); + } + words + } + } fn from_ark(value: Fr) -> Self { + #[cfg(not(feature = "openvm"))] let words = value.into_bigint().0; - Self([ + #[cfg(feature = "openvm")] + let words = value.0 .0; + let value = Self::new([ words[0] as u32, (words[0] >> 32) as u32, words[1] as u32, @@ -31,19 +111,48 @@ impl FastField { (words[2] >> 32) as u32, words[3] as u32, (words[3] >> 32) as u32, - ]) + ]); + #[cfg(not(feature = "openvm"))] + { + value + } + #[cfg(feature = "openvm")] + { + value.multiply(Self::MONTGOMERY_R_INVERSE) + } } fn into_ark(self) -> Fr { - Fr::from_bigint(BigInt([ - u64::from(self.0[0]) | (u64::from(self.0[1]) << 32), - u64::from(self.0[2]) | (u64::from(self.0[3]) << 32), - u64::from(self.0[4]) | (u64::from(self.0[5]) << 32), - u64::from(self.0[6]) | (u64::from(self.0[7]) << 32), - ])) - .expect("accelerated field operation returned a non-canonical value") + #[cfg(not(feature = "openvm"))] + let words = self.words(); + #[cfg(feature = "openvm")] + let words = { + let montgomery = self.multiply(Self::MONTGOMERY_R); + assert!( + montgomery.0.is_reduced(), + "The field value is not canonical" + ); + montgomery.words() + }; + let bigint = BigInt([ + u64::from(words[0]) | (u64::from(words[1]) << 32), + u64::from(words[2]) | (u64::from(words[3]) << 32), + u64::from(words[4]) | (u64::from(words[5]) << 32), + u64::from(words[6]) | (u64::from(words[7]) << 32), + ]); + #[cfg(not(feature = "openvm"))] + { + Fr::from_bigint(bigint) + .expect("accelerated field operation returned a non-canonical value") + } + #[cfg(feature = "openvm")] + { + // The product is reduced above and already uses the Montgomery representation. + Fr::new_unchecked(bigint) + } } + #[cfg(not(feature = "openvm"))] fn add(self, rhs: Self) -> Self { let mut output = [0u32; 8]; let mut carry = 0u64; @@ -60,22 +169,31 @@ impl FastField { Self(output) } + #[cfg(not(feature = "openvm"))] + #[inline(always)] fn double(self) -> Self { self.add(self) } - #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + #[cfg(not(feature = "openvm"))] fn multiply(self, rhs: Self) -> Self { - let mut output = [0u32; 8]; - risc0_bigint2::field::modmul_256(&self.0, &rhs.0, &MODULUS, &mut output); - Self(output) + Self::from_ark(self.into_ark() * rhs.into_ark()) + } + + #[cfg(all(feature = "openvm", test))] + #[inline(always)] + fn add(self, rhs: Self) -> Self { + Self(&self.0 + &rhs.0) } - #[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] + #[cfg(feature = "openvm")] + #[inline(always)] fn multiply(self, rhs: Self) -> Self { - Self::from_ark(self.into_ark() * rhs.into_ark()) + Self(&self.0 * &rhs.0) } + #[cfg(not(feature = "openvm"))] + #[inline(always)] fn pow_five(self) -> Self { let squared = self.multiply(self); let fourth = squared.multiply(squared); @@ -83,6 +201,7 @@ impl FastField { } } +#[cfg(not(feature = "openvm"))] fn less_than(lhs: &[u32; 8], rhs: &[u32; 8]) -> bool { for index in (0..8).rev() { if lhs[index] != rhs[index] { @@ -92,6 +211,7 @@ fn less_than(lhs: &[u32; 8], rhs: &[u32; 8]) -> bool { false } +#[cfg(not(feature = "openvm"))] fn subtract_modulus(value: &mut [u32; 8]) { let mut borrow = false; for index in 0..8 { @@ -107,19 +227,19 @@ const ROUNDS_F: usize = 8; const ROUNDS_P: usize = 56; const MAT_DIAG_M_1: [FastField; WIDTH] = [ - FastField([ + FastField::new([ 0x19d3b6e7, 0xb56821fd, 0x29ca1d7f, 0x0d03f989, 0x4bd9490c, 0x04b1e03b, 0x006ea38b, 0x10dc6e9c, ]), - FastField([ + FastField::new([ 0xb45a740b, 0xa86b38cf, 0xd4dd9b84, 0x99df9756, 0xa30b3bb5, 0x0149b3d0, 0x6a44df3e, 0x0c28145b, ]), - FastField([ + FastField::new([ 0x141cac15, 0x70067d00, 0x60e35961, 0xb21f75bb, 0x50392798, 0xb2c7645a, 0x38791518, 0x00544b83, ]), - FastField([ + FastField::new([ 0x33ee428b, 0x13bc5344, 0xb8fa8526, 0x52e105a3, 0x122789e3, 0x2e2e82eb, 0x5718386f, 0x222c0117, ]), @@ -127,378 +247,379 @@ const MAT_DIAG_M_1: [FastField; WIDTH] = [ const EXTERNAL_RC: [[FastField; WIDTH]; ROUNDS_F] = [ // First external [ - FastField([ + FastField::new([ 0x69ed23e5, 0x8b0878e2, 0x4edc2623, 0x02bb8674, 0xbd5e4a43, 0x48da1d39, 0x9450b068, 0x19b849f6, ]), - FastField([ + FastField::new([ 0x8dcf34d6, 0xad47f80c, 0x450acc1d, 0x20eb2cc7, 0x758f0a13, 0x7239347b, 0x27dd51bd, 0x265ddfe1, ]), - FastField([ + FastField::new([ 0xb497d8aa, 0x3dfc36ba, 0x5015c2aa, 0x4108ac84, 0x5e1e5162, 0xe0f66a54, 0x472f1809, 0x199750ec, ]), - FastField([ + FastField::new([ 0xc7f1cdf8, 0xd032f787, 0x5067f0ff, 0x4d743ea2, 0xf74302b1, 0x110f06a5, 0x65ac7208, 0x157ff3fe, ]), ], [ - FastField([ + FastField::new([ 0x6ac94902, 0xfe18f489, 0x692f8bee, 0x0b15c590, 0x5fca33f1, 0x5fd35ac4, 0x4569dd9c, 0x2e49c43c, ]), - FastField([ + FastField::new([ 0xfa2d1f1e, 0x2731345f, 0x73c24fa8, 0xcb2f0b69, 0x6d6506c3, 0x0d4aef2b, 0x98189052, 0x0e35fb89, ]), - FastField([ + FastField::new([ 0x02e0b996, 0xc6fe7230, 0x6d667ffe, 0xa9d9e780, 0x5e944f1b, 0x05f109ae, 0xb15c4f11, 0x251ad47c, ]), - FastField([ + FastField::new([ 0x9c22df4e, 0x563fa39d, 0xdd05e5f3, 0xf8beb56f, 0x60234641, 0x9873e971, 0x64d42836, 0x13da07dc, ]), ], [ - FastField([ + FastField::new([ 0x55fd4738, 0x46e7b890, 0x89d350cd, 0xa5539396, 0xccef7483, 0x3dc00c7d, 0xe650e6d2, 0x0c009b84, ]), - FastField([ + FastField::new([ 0xbefdca06, 0x203dec74, 0x6d535eb0, 0x04eb650c, 0x56f42d8b, 0x01992e39, 0xc63a854f, 0x011f16b1, ]), - FastField([ + FastField::new([ 0x3f367549, 0x85df0709, 0x467ad454, 0x2f3f78d0, 0x1daa7961, 0x209d9a56, 0x383a688f, 0x0ed69e5e, ]), - FastField([ + FastField::new([ 0x4c9f789b, 0x46367226, 0x5eb3d33f, 0x3aec507f, 0x472b6bbe, 0x21acad41, 0x7b0ce9e2, 0x04dba94a, ]), ], [ - FastField([ + FastField::new([ 0xd4fa28e8, 0xce732ff1, 0x4bb50bf7, 0x6036757d, 0x1c9d237b, 0x6eb09427, 0xd840f3a1, 0x0a3f2637, ]), - FastField([ + FastField::new([ 0x1182323f, 0xe54a485d, 0x569564b6, 0x39b1f075, 0x2fdb38fa, 0x8f8a1c50, 0x129eea19, 0x259a666f, ]), - FastField([ + FastField::new([ 0xede0d6a1, 0x7a32fdf7, 0x1038e515, 0x7745d427, 0x4ee3a47f, 0xd8e7d06a, 0xc9b2f4c6, 0x28bf7459, ]), - FastField([ + FastField::new([ 0x41432447, 0xec91bd69, 0xcce6a2ae, 0xc37c85bb, 0x489be8d4, 0x26ea200f, 0xf0570375, 0x0a1ca941, ]), ], // Second external [ - FastField([ + FastField::new([ 0xb1405d38, 0xf3b16ef2, 0x6be63b09, 0xab0fb85f, 0xc6f287f6, 0x77eb757b, 0x4b7a3e17, 0x1797130f, ]), - FastField([ + FastField::new([ 0x5decc6e5, 0x36c66855, 0x20156d4d, 0x8c7f497c, 0xbab59e60, 0x3306c85a, 0xc04170ae, 0x0a76225d, ]), - FastField([ + FastField::new([ 0x26a31a5c, 0x96174b53, 0x8acb6647, 0xf8fa76d4, 0x93209af6, 0xa1e77a7b, 0x1992d66b, 0x1fffb9ec, ]), - FastField([ + FastField::new([ 0x797b9c5f, 0x0611889b, 0xc6b9c609, 0x5f8fbba6, 0x8fa538d8, 0x53b57c33, 0xc15a3f28, 0x25721c4f, ]), ], [ - FastField([ + FastField::new([ 0xbfcaf75a, 0xeb63b982, 0x0705da95, 0xadb4c379, 0xba197216, 0x215e3d07, 0x2d5f7a41, 0x0c817fd4, ]), - FastField([ + FastField::new([ 0xe52b5a96, 0x2bc15866, 0xe00a2200, 0xdf8cf86c, 0xc24970b6, 0x9f7e13c2, 0x239915d3, 0x13abe3f5, ]), - FastField([ + FastField::new([ 0xb4d391ce, 0x92cd60ac, 0x29bdbd7a, 0x5c1bc3dc, 0x987a46c8, 0x12ef7f39, 0x546224ea, 0x2106feea, ]), - FastField([ + FastField::new([ 0x5bb0f959, 0x57e1b334, 0xc748bc71, 0xf1ca5a28, 0xa37dab49, 0xaaa79474, 0x68a746b6, 0x21ca8594, ]), ], [ - FastField([ + FastField::new([ 0x9e34185b, 0x8f1a4899, 0x0321662a, 0x2911d14d, 0x934194c6, 0x5cf1f0df, 0x5c1e6f0c, 0x05ccd625, ]), - FastField([ + FastField::new([ 0xb09490a4, 0xea28678c, 0x7fe44fe6, 0x16c4fb26, 0x674c4c88, 0xe464d846, 0x4b70a626, 0x0f0e34a6, ]), - FastField([ + FastField::new([ 0x2de0d4bf, 0x8f5b1a8a, 0x350d6483, 0x47dbfcfe, 0xa36d0e96, 0x6157794c, 0x4e25470c, 0x0558531a, ]), - FastField([ + FastField::new([ 0x961f1455, 0xb72f5864, 0x3f655a60, 0x924cadad, 0x57683d18, 0xceea1251, 0x173ed2fa, 0x09d3dca9, ]), ], [ - FastField([ + FastField::new([ 0xe5bd4335, 0x17d4c722, 0x8aaec486, 0xf23f92d6, 0xd03d218b, 0x493f866e, 0x4e8c0913, 0x0328cbd5, ]), - FastField([ + FastField::new([ 0x5329d34b, 0xee3347dd, 0x9798c648, 0xe79e7bcc, 0xa7094e07, 0x23a487b1, 0xe2aff0a2, 0x2bf07216, ]), - FastField([ + FastField::new([ 0x3fe412df, 0x111e11a6, 0xa6dffc82, 0xd6f78ed6, 0xcb76c316, 0x6499c583, 0x58006b73, 0x1daf345a, ]), - FastField([ + FastField::new([ 0x93d2c404, 0x391e6f22, 0xb2edc7ff, 0x1ef39039, 0x0e182361, 0x46b694c6, 0x2456aaa7, 0x17656347, ]), ], ]; const INTERNAL_RC: [FastField; ROUNDS_P] = [ - FastField([ + FastField::new([ 0x926361cf, 0xb43a26fd, 0x39f051dc, 0x5535ed15, 0xc5451285, 0x53d7fd4f, 0x8be0e930, 0x0c6f8f95, ]), - FastField([ + FastField::new([ 0x9caaf811, 0x84dd57e6, 0x08e296e0, 0xa9e8a007, 0x8ac9d90a, 0xd426e812, 0x3cd17578, 0x123106a9, ]), - FastField([ + FastField::new([ 0xcd2dee75, 0x7b074867, 0xf1e8f187, 0x5e8fa83f, 0xf8e84008, 0x7dd3ab52, 0xad9285d9, 0x26e1ba52, ]), - FastField([ + FastField::new([ 0x6a4ae2c5, 0x4471537e, 0xf9e09586, 0xbe4d8b7b, 0x47b9c97c, 0x18a64c5c, 0x7bd133de, 0x1cb55cad, ]), - FastField([ + FastField::new([ 0x6e9055d0, 0x7143f08e, 0x5060a41c, 0x2a53043d, 0x4bde7f6d, 0x0e2c7ce0, 0x6acd8f8e, 0x1dcd73e4, ]), - FastField([ + FastField::new([ 0x512e5574, 0xb12b9bb4, 0x0eb4e9b9, 0x0cda294a, 0x474a4def, 0xf5852f05, 0x2f6d9c66, 0x011003e3, ]), - FastField([ + FastField::new([ 0x2287ae8c, 0xd7c508dd, 0x3f58bafe, 0xbadfe590, 0x03a57dfe, 0x9ad5f20d, 0xc1d10ab2, 0x2b1e809a, ]), - FastField([ + FastField::new([ 0x7bcec0a5, 0xeaa69ae8, 0xab2fc5fa, 0xef995d05, 0x5ee17ed0, 0x9fb4dac3, 0x85b73599, 0x2539de17, ]), - FastField([ + FastField::new([ 0x1d77951d, 0x43982cb1, 0x1c86d46e, 0xf4e1c3d4, 0x2b3e0a0e, 0x26497f22, 0x2ef8ee01, 0x0c246c5a, ]), - FastField([ + FastField::new([ 0xd03b527b, 0x3f0305f5, 0xad1a1c2f, 0xbb09e6a6, 0x7c0632ed, 0x5408148f, 0x974f68e9, 0x192089c4, ]), - FastField([ + FastField::new([ 0xb5a60d85, 0x6d8fdc2f, 0x91096b75, 0x8529097d, 0xeb0d0c05, 0x6a0ee36e, 0xab68b2f0, 0x1eae0ad8, ]), - FastField([ + FastField::new([ 0xc5d06bfb, 0x9768bd98, 0x0dee99e6, 0xdb6e2fdc, 0x872abc88, 0xe46f8282, 0xd0e22179, 0x179190e5, ]), - FastField([ + FastField::new([ 0xa9b3cd1c, 0x6cafe794, 0xb00f31bf, 0x14528f7d, 0x7ac4b832, 0x76e9a81c, 0x90767325, 0x29bb9e2c, ]), - FastField([ + FastField::new([ 0x6e691e08, 0xb10e590e, 0x882aac35, 0x52652645, 0x2464a90d, 0x403efd0c, 0x42207599, 0x225d394e, ]), - FastField([ + FastField::new([ 0x4b23fd59, 0xe09efd45, 0x451c087d, 0x2be13557, 0x55b44453, 0x753d2380, 0x3c25c8cf, 0x06476062, ]), - FastField([ + FastField::new([ 0x8f6b5b87, 0x922910a7, 0x42a75c10, 0x4d67f4bf, 0x716d8a39, 0x7f301c4b, 0x01df92e8, 0x10ba3a0e, ]), - FastField([ + FastField::new([ 0x3f21471c, 0x361b7769, 0xc242eb9d, 0xcb511bc0, 0xb0c2a801, 0x4f9c6e96, 0x3f8451b2, 0x0e070bf5, ]), - FastField([ + FastField::new([ 0x4de252fb, 0xa7f92101, 0xd2491d8a, 0xccd6cb11, 0x93821a73, 0xd39755ff, 0xb051b04d, 0x1b94cd61, ]), - FastField([ + FastField::new([ 0x7d74070b, 0x0487b5aa, 0x5713bb05, 0x9d4e917d, 0x2e70230f, 0xe148787a, 0xafb8c744, 0x1d7cb39b, ]), - FastField([ + FastField::new([ 0x303b17db, 0xbb74ac1f, 0x1829f701, 0x8785c296, 0x980c80ff, 0x9117d0fe, 0xbd1ab4f6, 0x2ec93189, ]), - FastField([ + FastField::new([ 0x83517926, 0x82ea46bd, 0x9ae07a90, 0xeac404a1, 0x5b86275b, 0xa692bb82, 0xdd36d277, 0x2db366bf, ]), - FastField([ + FastField::new([ 0x960711b8, 0xdc99cec6, 0x8450359a, 0x98527542, 0x86a68532, 0x69655cf1, 0x485db062, 0x062100eb, ]), - FastField([ + FastField::new([ 0x41f5a59b, 0x00c567bf, 0xfa59e4f9, 0x20243f92, 0x8244ca11, 0x570e7f1e, 0x66614aaa, 0x0761d33c, ]), - FastField([ + FastField::new([ 0x4855ad0d, 0xf7a72e49, 0x0f7de4cc, 0x5d78608a, 0x034e3f31, 0x2c2705aa, 0x114d1399, 0x20fc411a, ]), - FastField([ + FastField::new([ 0x7250bc5a, 0xc3a30f31, 0xb3effb5f, 0x102c67e8, 0x9ab219ba, 0xadd9ec4e, 0xa4bdfcb5, 0x25b5c004, ]), - FastField([ + FastField::new([ 0x62b37f4b, 0xd87e7dff, 0x8474155a, 0x038b186d, 0x6df6f5ed, 0xa494e58f, 0x278ed632, 0x23b1822d, ]), - FastField([ + FastField::new([ 0xcc2f69e0, 0x16102a29, 0xfcfcccaa, 0x0f14d13b, 0x012499bf, 0x606c4ba9, 0x5c3f9493, 0x22734b4c, ]), - FastField([ + FastField::new([ 0xad795ce5, 0x54413d3f, 0x9aa36102, 0xe5bdff40, 0x33492347, 0xe27a74dc, 0x09eb30b7, 0x26c0c8fe, ]), - FastField([ + FastField::new([ 0x348ccad9, 0xbbd626df, 0x3a809829, 0x196be308, 0xfa1fbb26, 0xe88eac03, 0xb6bd7bba, 0x070dd0cc, ]), - FastField([ + FastField::new([ 0xfd4250da, 0x6067c4eb, 0x46d8c5ad, 0xc2c0a6de, 0xbb28c3be, 0xb043ba78, 0xdb329b6f, 0x12b6595b, ]), - FastField([ + FastField::new([ 0xb7e8d729, 0x5e33d95b, 0x275c671c, 0xc06fca9b, 0xa5876c11, 0x3bec30e7, 0xf76283d6, 0x248d97d7, ]), - FastField([ + FastField::new([ 0xbd9baaaa, 0x106d15d9, 0x9ddde4aa, 0x8b45eb75, 0x4cc93931, 0x16fc6fd6, 0x9d463b08, 0x1a306d43, ]), - FastField([ + FastField::new([ 0xec7c56cf, 0x0d62d3d6, 0xdc27821b, 0xf4f1b54d, 0x21cb4621, 0xced7c004, 0x2e3c38da, 0x28a8f837, ]), - FastField([ + FastField::new([ 0xe1e2ce7e, 0xbc852183, 0xc829f388, 0x071ce320, 0x24d43294, 0xbb35152f, 0x17f9a8a8, 0x00949757, ]), - FastField([ + FastField::new([ 0xdb2e8d65, 0xf4103246, 0xf653ae83, 0x593f74d4, 0x716480d3, 0x80fde60d, 0x3aa78f7d, 0x04d5ee4c, ]), - FastField([ + FastField::new([ 0x2efde187, 0xd08495c1, 0x8822cc76, 0xc7bef54b, 0xb8ed2269, 0x6349ad6f, 0xaa03d433, 0x2a6cf5e9, ]), - FastField([ + FastField::new([ 0xefcba3f3, 0xbaae48d7, 0x08fd6e43, 0xf7921808, 0xe19ddeb7, 0x9274da43, 0xaab960ba, 0x2304d31e, ]), - FastField([ + FastField::new([ 0xd199f0b0, 0xe1c11d39, 0x0726fcb4, 0xbff08a7e, 0x85817249, 0xd5e70097, 0x65a4b2a6, 0x03fd9ac8, ]), - FastField([ + FastField::new([ 0xd63b0b64, 0x3f7954d4, 0x20919307, 0x798afc3a, 0x55ee5044, 0x2248404d, 0xed52bbda, 0x00b7258d, ]), - FastField([ + FastField::new([ 0x65e92d9a, 0x6272c5ca, 0xf3298db3, 0xb13d3a74, 0xd4bf65eb, 0xec38fca2, 0xa0771799, 0x159f81ad, ]), - FastField([ + FastField::new([ 0x4264431f, 0x71e144cf, 0xa25f0c54, 0x9000130e, 0xbc28e3bb, 0x50237a75, 0x437fbc85, 0x1ef90e67, ]), - FastField([ + FastField::new([ 0x2932e30d, 0x95a79ed8, 0x176b08ec, 0x8df739bc, 0x41a2d256, 0x196b49aa, 0x515e5ff0, 0x1e65f838, ]), - FastField([ + FastField::new([ 0x8c94c33f, 0x6575c106, 0x570e1f82, 0xb18c844e, 0xd079ba74, 0xec6ce768, 0xef3a166c, 0x2b1b045d, ]), - FastField([ + FastField::new([ 0x168bb173, 0xf1c6e07c, 0xbef715e3, 0x65dc2d73, 0x109229c1, 0x402543b1, 0x3ceb0ff6, 0x0832e575, ]), - FastField([ + FastField::new([ 0x90b6ad16, 0xc5a8e3c3, 0xe8b6451b, 0xb1b841c2, 0xa37d41ba, 0x6b762ae0, 0xcedfb3dc, 0x02f614e9, ]), - FastField([ + FastField::new([ 0x7e7ed705, 0x0f6a0be2, 0x77bedff4, 0x7370ebb7, 0x362cad96, 0xdd640b8e, 0x8bd46a60, 0x0e2427d3, ]), - FastField([ + FastField::new([ 0x9214a53a, 0x0768bbe2, 0x98c3c7c5, 0x049f0ec0, 0x14e7ce79, 0xeb7c84d4, 0x7c670b6d, 0x0493630b, ]), - FastField([ + FastField::new([ 0x5327cea9, 0x3dc06cc8, 0x55d5461a, 0x6bb15153, 0x7066c5a2, 0x4decdab1, 0xe8e48267, 0x22ead100, ]), - FastField([ + FastField::new([ 0x6d2a6f16, 0xe5084e0b, 0x5626d04d, 0x583f1ae3, 0xd2554d48, 0xaae2626e, 0x655b42cd, 0x25b3e56e, ]), - FastField([ + FastField::new([ 0x0cf6f9d0, 0x4b4fdc0a, 0x349e4c58, 0xb599c336, 0xe8ff13db, 0x5837a6cd, 0xda8836ef, 0x1e32752a, ]), - FastField([ + FastField::new([ 0x74d412e5, 0x72a98640, 0xf05078f6, 0x23c00995, 0xf3c3455b, 0xc50f68f6, 0xc15a387c, 0x2fa2a871, ]), - FastField([ + FastField::new([ 0xa7d83505, 0xcd18e7c7, 0x661bab7f, 0x54ccbf10, 0x311e889f, 0x278e1db7, 0x9a4424c9, 0x2f569b8a, ]), - FastField([ + FastField::new([ 0xb246b43d, 0x44165374, 0x332ffd21, 0xa7df93f7, 0x0234c518, 0x531ade53, 0x110a8fdd, 0x044cb455, ]), - FastField([ + FastField::new([ 0xa5319025, 0x78ddc723, 0xadfe1181, 0x91fe8c90, 0x7f2e42b1, 0x42024615, 0x93906d5d, 0x227808de, ]), - FastField([ + FastField::new([ 0xa6800355, 0x8579d2e7, 0xe090ad4a, 0x5d03781a, 0x87357986, 0x623adead, 0x34e046bc, 0x02fcca29, ]), - FastField([ + FastField::new([ 0x0d8befac, 0xcbec2e06, 0xab91a8dd, 0xbad3f3c5, 0x344a1d36, 0x6abccceb, 0xac120b87, 0x0ef915f0, ]), ]; +#[cfg(not(feature = "openvm"))] fn matmul_external(state: &mut [FastField; WIDTH]) { let t0 = state[0].add(state[1]); let t1 = state[2].add(state[3]); @@ -514,6 +635,7 @@ fn matmul_external(state: &mut [FastField; WIDTH]) { state[3] = t4; } +#[cfg(not(feature = "openvm"))] fn external_round(state: &mut [FastField; WIDTH], constants: &[FastField; WIDTH]) { for index in 0..WIDTH { state[index] = state[index].add(constants[index]).pow_five(); @@ -521,6 +643,7 @@ fn external_round(state: &mut [FastField; WIDTH], constants: &[FastField; WIDTH] matmul_external(state); } +#[cfg(not(feature = "openvm"))] fn internal_round(state: &mut [FastField; WIDTH], constant: FastField) { state[0] = state[0].add(constant).pow_five(); let sum = state.iter().copied().fold(FastField::ZERO, FastField::add); @@ -529,6 +652,60 @@ fn internal_round(state: &mut [FastField; WIDTH], constant: FastField) { } } +#[cfg(feature = "openvm")] +#[inline(always)] +fn pow_five_assign(value: &mut FastField) { + let base = value.0; + value.0.square_assign(); + value.0.square_assign(); + value.0 *= &base; +} + +#[cfg(feature = "openvm")] +#[inline(always)] +fn matmul_external(state: &mut [FastField; WIDTH]) { + let mut t0 = &state[0].0 + &state[1].0; + let mut t1 = &state[2].0 + &state[3].0; + let mut t2 = state[1].0.double(); + t2 += &t1; + let mut t3 = state[3].0.double(); + t3 += &t0; + t1.double_assign(); + t1.double_assign(); + t1 += &t3; + t0.double_assign(); + t0.double_assign(); + t0 += &t2; + state[0].0 = &t3 + &t0; + state[1].0 = t0; + state[2].0 = &t2 + &t1; + state[3].0 = t1; +} + +#[cfg(feature = "openvm")] +#[inline(always)] +fn external_round(state: &mut [FastField; WIDTH], constants: &[FastField; WIDTH]) { + for (value, constant) in state.iter_mut().zip(constants) { + value.0 += &constant.0; + pow_five_assign(value); + } + matmul_external(state); +} + +#[cfg(feature = "openvm")] +#[inline(always)] +fn internal_round(state: &mut [FastField; WIDTH], constant: FastField) { + state[0].0 += &constant.0; + pow_five_assign(&mut state[0]); + let mut sum = &state[0].0 + &state[1].0; + sum += &state[2].0; + sum += &state[3].0; + for (value, diagonal) in state.iter_mut().zip(&MAT_DIAG_M_1) { + value.0 *= &diagonal.0; + value.0 += ∑ + } +} + pub(super) fn permutation(input: &[Fr; WIDTH]) -> [Fr; WIDTH] { let mut state = input.map(FastField::from_ark); matmul_external(&mut state); @@ -557,6 +734,25 @@ mod tests { Fr::from_le_bytes_mod_order(&rng.random::<[u8; 32]>()) } + #[test] + fn accelerated_field_conversion_matches_canonical_words() { + let mut rng = ChaCha8Rng::seed_from_u64(0xc0eff); + let mut inputs = vec![Fr::from(0), Fr::from(1), -Fr::from(1)]; + inputs.extend((0..100).map(|_| random_field(&mut rng))); + for input in inputs { + let accelerated = FastField::from_ark(input); + assert_eq!(accelerated.into_ark(), input); + let words = accelerated.words(); + let canonical = BigInt([ + u64::from(words[0]) | (u64::from(words[1]) << 32), + u64::from(words[2]) | (u64::from(words[3]) << 32), + u64::from(words[4]) | (u64::from(words[5]) << 32), + u64::from(words[6]) | (u64::from(words[7]) << 32), + ]); + assert_eq!(canonical, input.into_bigint()); + } + } + #[test] fn accelerated_field_addition_reduces_at_the_modulus() { let modulus_minus_one = Fr::from_bigint(BigInt([ diff --git a/crates/scripts/update_revs.sh b/crates/scripts/update_revs.sh index 004a65fda9..729d32c1f1 100755 --- a/crates/scripts/update_revs.sh +++ b/crates/scripts/update_revs.sh @@ -8,7 +8,6 @@ EXCLUDE_PATHS=( "*/.interfold/caches/*" "*/target/*" "*/node_modules/*" - "*/risc0-ethereum/*" ) # Build exclude arguments diff --git a/crates/support-scripts/ctl/compile b/crates/support-scripts/ctl/compile deleted file mode 100755 index 748542f656..0000000000 --- a/crates/support-scripts/ctl/compile +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -"$SCRIPT_DIR/container" ./scripts/container/build.sh diff --git a/crates/support-scripts/ctl/container b/crates/support-scripts/ctl/container deleted file mode 100755 index f00cb5a52c..0000000000 --- a/crates/support-scripts/ctl/container +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash - -# Resolve the revision from this CLI binary, not from a running node. In an Interfold project, -# `interfold rev` is normally forwarded to the node daemon and can therefore return the revision -# of an older node while a new CLI is starting its matching support image. -GIT_SHA=$(cd / && interfold rev) -CONTAINER_NAME="e3-support.1" -IMAGE_REPOSITORY="${E3_SUPPORT_IMAGE_REPOSITORY:-ghcr.io/theinterfold/e3-support}" -IMAGE="$IMAGE_REPOSITORY:$GIT_SHA" -CACHE_PREFIX="e3-support" - -SUPPORT_ENVIRONMENT=( - RISC0_DEV_MODE RPC_URL PRIVATE_KEY PINATA_JWT IPFS_GATEWAY_URL PROGRAM_URL BOUNDLESS_ONCHAIN - BOUNDLESS_MIN_PRICE_ETH BOUNDLESS_MAX_PRICE_ETH BOUNDLESS_TIMEOUT_SECS - BOUNDLESS_LOCK_TIMEOUT_SECS BOUNDLESS_RAMP_UP_SECS BOUNDLESS_LOCK_COLLATERAL_ZKC - BOUNDLESS_INPUT_ENCODING -) -DOCKER_ENVIRONMENT=() -for name in "${SUPPORT_ENVIRONMENT[@]}"; do - if [[ -n "${!name:-}" ]]; then - # Giving Docker only the name copies the inherited value without placing it in argv. - DOCKER_ENVIRONMENT+=(--env "$name") - fi -done - -# Use the support image that matches the CLI revision. -# This match prevents incompatible support script changes after a CLI update. -# Pull the image only when the image is not available locally. -if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then - echo "Support image not found locally. Pulling $IMAGE..." - if ! docker pull "$IMAGE"; then - echo "Support image $IMAGE is unavailable. Verify the image tag and registry access." - exit 1 - fi -fi - -# Function to cleanup -cleanup() { - echo "Stopping container and processes..." - # Try to gracefully stop the container first - docker exec "$CONTAINER_NAME" pkill -SIGTERM e3-support-app 2>/dev/null || true - sleep 2 - # Force stop if still running - docker exec "$CONTAINER_NAME" pkill -SIGKILL e3-support-app 2>/dev/null || true - docker stop "$CONTAINER_NAME" 2>/dev/null || true -} - -# Set trap for signals -trap cleanup EXIT INT TERM - -mkdir -p "$(pwd)/.interfold/caches"/{target,registry,git,risc0-cache,risc0-circuits} -mkdir -p "$(pwd)/.interfold/generated"/{contracts,tests} -chmod -R 777 "$(pwd)/.interfold/caches" -chmod -R 777 "$(pwd)/.interfold/generated" - -if [ -t 0 ]; then - TTY_FLAGS="-it" -else - TTY_FLAGS="" -fi - -if docker ps -q -f name="$CONTAINER_NAME" | grep -q .; then - echo "Running exec $IMAGE..." - docker exec $TTY_FLAGS "${DOCKER_ENVIRONMENT[@]}" "$CONTAINER_NAME" bash -c "$*" -else - echo "Running start $IMAGE..." - # --network=host does not work on macos for allowing the container to access - # the local machine. `--add-host...` is adding host.local to the hosts file - # in the docker container we can then replace localhost and 127.0.0.1 - # from the input callback url so calls redirect to gateway. - # This should in theory be crossplatform - # However on linux the user must allow incoming connections from Docker's bridge network 172.17.0.0/16 through their firewall. - docker run $TTY_FLAGS --rm \ - --name "$CONTAINER_NAME" \ - --platform linux/amd64 \ - --add-host=host.local:host-gateway \ - "${DOCKER_ENVIRONMENT[@]}" \ - -p 13151:13151 \ - -v "$(pwd)/.interfold/generated/contracts:/app/contracts:rw" \ - -v "$(pwd)/tests:/app/tests" \ - -v "$(pwd)/.interfold/caches/target:/app/target" \ - -v "$(pwd)/.interfold/caches/registry:/home/devuser/.cargo/registry" \ - -v "$(pwd)/.interfold/caches/git:/home/devuser/.cargo/git" \ - -v "$(pwd)/.interfold/caches/risc0-cache:/home/devuser/.risc0/cache" \ - -v "$(pwd)/.interfold/caches/risc0-circuits:/home/devuser/.risc0/circuits" \ - -v "${CACHE_PREFIX}-cargo-cache:/usr/local/cargo" \ - "$IMAGE" bash -c "$*" -fi diff --git a/crates/support-scripts/ctl/shell b/crates/support-scripts/ctl/shell deleted file mode 100755 index 42a16f0922..0000000000 --- a/crates/support-scripts/ctl/shell +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -"$SCRIPT_DIR/container" bash diff --git a/crates/support-scripts/ctl/start b/crates/support-scripts/ctl/start deleted file mode 100755 index d8de24b309..0000000000 --- a/crates/support-scripts/ctl/start +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash - -# Configuration normally arrives through the environment so credentials do not appear in process -# arguments. Keep the flags for direct, backwards-compatible use. - -while [[ $# -gt 0 ]]; do - case $1 in - --risc0-dev-mode) - RISC0_DEV_MODE="$2" - shift 2 - ;; - --rpc-url) - RPC_URL="$2" - shift 2 - ;; - --private-key) - PRIVATE_KEY="$2" - shift 2 - ;; - --pinata-jwt) - PINATA_JWT="$2" - shift 2 - ;; - --ipfs-gateway-url) - IPFS_GATEWAY_URL="$2" - shift 2 - ;; - --program-url) - PROGRAM_URL="$2" - shift 2 - ;; - --boundless-onchain) - BOUNDLESS_ONCHAIN="$2" - shift 2 - ;; - --boundless-min-price-eth) - BOUNDLESS_MIN_PRICE_ETH="$2" - shift 2 - ;; - --boundless-max-price-eth) - BOUNDLESS_MAX_PRICE_ETH="$2" - shift 2 - ;; - --boundless-timeout-secs) - BOUNDLESS_TIMEOUT_SECS="$2" - shift 2 - ;; - --boundless-lock-timeout-secs) - BOUNDLESS_LOCK_TIMEOUT_SECS="$2" - shift 2 - ;; - --boundless-ramp-up-secs) - BOUNDLESS_RAMP_UP_SECS="$2" - shift 2 - ;; - --boundless-lock-collateral-zkc) - BOUNDLESS_LOCK_COLLATERAL_ZKC="$2" - shift 2 - ;; - *) - echo "Unknown argument: $1" - exit 1 - ;; - esac -done - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONTAINER_ARGS=("./scripts/container/start.sh") - -if [[ -n "${RPC_URL:-}" && -z "${PRIVATE_KEY:-}" ]] || [[ -z "${RPC_URL:-}" && -n "${PRIVATE_KEY:-}" ]]; then - echo "Error: Both --rpc-url and --private-key must be provided together, or neither" - exit 1 -fi - -export RISC0_DEV_MODE RPC_URL PRIVATE_KEY PINATA_JWT IPFS_GATEWAY_URL PROGRAM_URL BOUNDLESS_ONCHAIN -export BOUNDLESS_MIN_PRICE_ETH BOUNDLESS_MAX_PRICE_ETH -export BOUNDLESS_TIMEOUT_SECS BOUNDLESS_LOCK_TIMEOUT_SECS BOUNDLESS_RAMP_UP_SECS -export BOUNDLESS_LOCK_COLLATERAL_ZKC - -exec "$SCRIPT_DIR/container" "${CONTAINER_ARGS[@]}" diff --git a/crates/support-scripts/ctl/upload b/crates/support-scripts/ctl/upload deleted file mode 100755 index 9c7cc03251..0000000000 --- a/crates/support-scripts/ctl/upload +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# Configuration normally arrives through the environment so the Pinata token does not appear in -# process arguments. Keep the flags for direct, backwards-compatible use. -while [[ $# -gt 0 ]]; do - case $1 in - --pinata-jwt) - PINATA_JWT="$2" - shift 2 - ;; - --ipfs-gateway-url) - IPFS_GATEWAY_URL="$2" - shift 2 - ;; - *) - echo "Unknown argument: $1" - exit 1 - ;; - esac -done - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONTAINER_ARGS=("./scripts/container/upload.sh") -export PINATA_JWT IPFS_GATEWAY_URL - -exec "$SCRIPT_DIR/container" "${CONTAINER_ARGS[@]}" diff --git a/crates/support-scripts/src/lib.rs b/crates/support-scripts/src/lib.rs index 241e6c8a1d..c99172e2d0 100644 --- a/crates/support-scripts/src/lib.rs +++ b/crates/support-scripts/src/lib.rs @@ -6,7 +6,7 @@ mod program; mod program_dev; -mod program_risc0; +mod program_openvm; mod traits; mod utils; @@ -16,7 +16,6 @@ use program::ProgramSupport; use std::env; use tokio::fs; use traits::ProgramSupportApi; -use utils::{ensure_script_exists, run_bash_script}; pub async fn program_compile(program_config: ProgramConfig, is_dev: Option) -> Result<()> { ProgramSupport::new(program_config, is_dev).compile().await @@ -26,20 +25,6 @@ pub async fn program_start(program_config: ProgramConfig, is_dev: Option) ProgramSupport::new(program_config, is_dev).start().await } -/// Upload the compiled program to Pinata IPFS -pub async fn program_upload(program_config: ProgramConfig, is_dev: Option) -> Result<()> { - ProgramSupport::new(program_config, is_dev).upload().await -} - -/// Open up a shell in the docker container -pub async fn program_shell() -> Result<()> { - let cwd = env::current_dir()?; - let script = cwd.join(".interfold/support/ctl/shell"); - ensure_script_exists(&script).await?; - run_bash_script(&cwd, &script, &[]).await?; - Ok(()) -} - /// Purge all build caches from support pub async fn program_cache_purge() -> Result<()> { let cwd = env::current_dir()?; diff --git a/crates/support-scripts/src/program.rs b/crates/support-scripts/src/program.rs index 52e486637b..83e5ceb7ce 100644 --- a/crates/support-scripts/src/program.rs +++ b/crates/support-scripts/src/program.rs @@ -9,7 +9,7 @@ use async_trait::async_trait; use e3_config::ProgramConfig; use crate::{ - program_dev::ProgramSupportDev, program_risc0::ProgramSupportRisc0, traits::ProgramSupportApi, + program_dev::ProgramSupportDev, program_openvm::ProgramSupportOpenVm, traits::ProgramSupportApi, }; fn get_mode(config: ProgramConfig, mode: Option) -> bool { @@ -21,7 +21,7 @@ fn get_mode(config: ProgramConfig, mode: Option) -> bool { pub enum ProgramSupport { Dev(ProgramSupportDev), - Risc0(ProgramSupportRisc0), + OpenVm(ProgramSupportOpenVm), } impl ProgramSupport { @@ -29,7 +29,7 @@ impl ProgramSupport { if get_mode(config.clone(), mode) { ProgramSupport::Dev(ProgramSupportDev(config)) } else { - ProgramSupport::Risc0(ProgramSupportRisc0(config)) + ProgramSupport::OpenVm(ProgramSupportOpenVm(config)) } } } @@ -39,20 +39,38 @@ impl ProgramSupportApi for ProgramSupport { async fn compile(&self) -> Result<()> { match self { ProgramSupport::Dev(s) => s.compile().await, - ProgramSupport::Risc0(s) => s.compile().await, + ProgramSupport::OpenVm(s) => s.compile().await, } } async fn start(&self) -> Result<()> { match self { ProgramSupport::Dev(s) => s.start().await, - ProgramSupport::Risc0(s) => s.start().await, + ProgramSupport::OpenVm(s) => s.start().await, } } +} - async fn upload(&self) -> Result<()> { - match self { - ProgramSupport::Dev(s) => s.upload().await, - ProgramSupport::Risc0(s) => s.upload().await, - } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_backend_is_openvm() { + assert!(matches!( + ProgramSupport::new(ProgramConfig::default(), None), + ProgramSupport::OpenVm(_) + )); + } + + #[test] + fn unproved_execution_requires_an_explicit_flag() { + assert!(matches!( + ProgramSupport::new(ProgramConfig::default(), Some(true)), + ProgramSupport::Dev(_) + )); + assert!(matches!( + ProgramSupport::new(ProgramConfig::default(), Some(false)), + ProgramSupport::OpenVm(_) + )); } } diff --git a/crates/support-scripts/src/program_dev.rs b/crates/support-scripts/src/program_dev.rs index 7f2f22d357..2217b23313 100644 --- a/crates/support-scripts/src/program_dev.rs +++ b/crates/support-scripts/src/program_dev.rs @@ -33,12 +33,4 @@ impl ProgramSupportApi for ProgramSupportDev { run_bash_script(&cwd, &script, &[]).await?; Ok(()) } - - async fn upload(&self) -> Result<()> { - let cwd = env::current_dir()?; - let script = cwd.join(".interfold/support/ctl/upload"); - ensure_script_exists(&script).await?; - run_bash_script(&cwd, &script, &[]).await?; - Ok(()) - } } diff --git a/crates/support-scripts/src/program_openvm.rs b/crates/support-scripts/src/program_openvm.rs new file mode 100644 index 0000000000..e30e3ff87a --- /dev/null +++ b/crates/support-scripts/src/program_openvm.rs @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +use crate::{traits::ProgramSupportApi, utils::run_bash_script_with_env}; +use anyhow::{ensure, Context, Result}; +use async_trait::async_trait; +use e3_config::ProgramConfig; + +pub struct ProgramSupportOpenVm(pub ProgramConfig); + +impl ProgramSupportOpenVm { + async fn run(&self, action: &str) -> Result<()> { + let config = self.0.openvm().context( + "Set program.openvm with the repository, prover_bin, and prover_config paths", + )?; + ensure!( + config.repository.is_absolute(), + "program.openvm.repository must be an absolute path" + ); + let script = config.repository.join("scripts/run-openvm.sh"); + ensure!( + script.is_file(), + "The OpenVM build script is missing from the configured repository" + ); + let environment = vec![ + ( + "OPENVM_PROVER_BIN".to_owned(), + config.prover_bin.to_string_lossy().into_owned(), + ), + ( + "OPENVM_PROVER_CONFIG".to_owned(), + config.prover_config.to_string_lossy().into_owned(), + ), + ]; + run_bash_script_with_env(&config.repository, &script, &[action], &environment).await?; + Ok(()) + } +} + +#[async_trait] +impl ProgramSupportApi for ProgramSupportOpenVm { + async fn compile(&self) -> Result<()> { + self.run("service-build").await + } + async fn start(&self) -> Result<()> { + self.run("service-start").await + } +} diff --git a/crates/support-scripts/src/program_risc0.rs b/crates/support-scripts/src/program_risc0.rs deleted file mode 100644 index e6ff75c0f0..0000000000 --- a/crates/support-scripts/src/program_risc0.rs +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use std::env; - -use crate::utils::run_bash_script_with_env; -use crate::{ensure_script_exists, run_bash_script, traits::ProgramSupportApi}; -use anyhow::{bail, Result}; -use async_trait::async_trait; -use e3_config::ProgramConfig; - -pub struct ProgramSupportRisc0(pub ProgramConfig); - -#[async_trait] -impl ProgramSupportApi for ProgramSupportRisc0 { - /// Run the docker container compile script - async fn compile(&self) -> Result<()> { - let cwd = env::current_dir()?; - let script = cwd.join(".interfold/support/ctl/compile"); - ensure_script_exists(&script).await?; - run_bash_script(&cwd, &script, &[]).await?; - Ok(()) - } - - /// Run the docker container start script - async fn start(&self) -> Result<()> { - let cwd = env::current_dir()?; - let script = cwd.join(".interfold/support/ctl/start"); - ensure_script_exists(&script).await?; - - let Some(risc0_config) = self.0.risc0() else { - bail!("start must be run with risc0 config available"); - }; - - let mut environment = vec![( - "RISC0_DEV_MODE".to_owned(), - risc0_config.risc0_dev_mode.to_string(), - )]; - - // Boundless support - if let Some(boundless) = &risc0_config.boundless { - environment.extend([ - ("RPC_URL".to_owned(), boundless.rpc_url.clone()), - ("PRIVATE_KEY".to_owned(), boundless.private_key.clone()), - ]); - - if let Some(jwt) = &boundless.pinata_jwt { - environment.push(("PINATA_JWT".to_owned(), jwt.clone())); - } - - if let Some(url) = &boundless.ipfs_gateway_url { - environment.push(("IPFS_GATEWAY_URL".to_owned(), url.clone())); - } - - if let Some(url) = &boundless.program_url { - environment.push(("PROGRAM_URL".to_owned(), url.clone())); - } - - let onchain = if boundless.onchain { "true" } else { "false" }; - environment.push(("BOUNDLESS_ONCHAIN".to_owned(), onchain.to_owned())); - - if let Some(v) = boundless.min_price_eth { - environment.push(("BOUNDLESS_MIN_PRICE_ETH".to_owned(), v.to_string())); - } - if let Some(v) = boundless.max_price_eth { - environment.push(("BOUNDLESS_MAX_PRICE_ETH".to_owned(), v.to_string())); - } - if let Some(v) = boundless.timeout_secs { - environment.push(("BOUNDLESS_TIMEOUT_SECS".to_owned(), v.to_string())); - } - if let Some(v) = boundless.lock_timeout_secs { - environment.push(("BOUNDLESS_LOCK_TIMEOUT_SECS".to_owned(), v.to_string())); - } - if let Some(v) = boundless.ramp_up_secs { - environment.push(("BOUNDLESS_RAMP_UP_SECS".to_owned(), v.to_string())); - } - if let Some(v) = boundless.lock_collateral_zkc { - environment.push(("BOUNDLESS_LOCK_COLLATERAL_ZKC".to_owned(), v.to_string())); - } - } - - run_bash_script_with_env(&cwd, &script, &[], &environment).await?; - Ok(()) - } - - /// Upload the compiled program to Pinata IPFS - async fn upload(&self) -> Result<()> { - let cwd = env::current_dir()?; - let script = cwd.join(".interfold/support/ctl/upload"); - ensure_script_exists(&script).await?; - - let mut environment = vec![]; - - if let Some(risc0_config) = self.0.risc0() { - if let Some(boundless) = &risc0_config.boundless { - if let Some(jwt) = &boundless.pinata_jwt { - environment.push(("PINATA_JWT".to_owned(), jwt.clone())); - } - if let Some(url) = &boundless.ipfs_gateway_url { - environment.push(("IPFS_GATEWAY_URL".to_owned(), url.clone())); - } - } - } - - run_bash_script_with_env(&cwd, &script, &[], &environment).await?; - Ok(()) - } -} diff --git a/crates/support-scripts/src/traits.rs b/crates/support-scripts/src/traits.rs index 2145e6a4d8..ab80dca5d9 100644 --- a/crates/support-scripts/src/traits.rs +++ b/crates/support-scripts/src/traits.rs @@ -11,5 +11,4 @@ use async_trait::async_trait; pub trait ProgramSupportApi { async fn compile(&self) -> Result<()>; async fn start(&self) -> Result<()>; - async fn upload(&self) -> Result<()>; } diff --git a/crates/support-scripts/tests/container.sh b/crates/support-scripts/tests/container.sh deleted file mode 100755 index 332b7dcf50..0000000000 --- a/crates/support-scripts/tests/container.sh +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -REPOSITORY_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" -START_SCRIPT="$REPOSITORY_ROOT/crates/support-scripts/ctl/start" -TEST_REVISION="abc123456" -TEST_PARENT="${TMPDIR:-/tmp}" -TEST_PARENT="${TEST_PARENT%/}" -TEST_DIRECTORIES=() - -cleanup() { - local directory - for directory in "${TEST_DIRECTORIES[@]}"; do - case "$directory" in - "$TEST_PARENT"/e3-support-test.*) rm -rf -- "$directory" ;; - *) - echo "Refusing to remove unexpected test directory: $directory" >&2 - return 1 - ;; - esac - done -} -trap cleanup EXIT - -interfold() { - if [[ "${1:-}" != "rev" ]]; then - return 1 - fi - if [[ "$PWD" == "/" ]]; then - printf '%s\n' "$TEST_REVISION" - else - printf '%s\n' "running-node-revision" - fi -} - -docker() { - if [[ "${1:-}" == "image" && "${2:-}" == "inspect" ]]; then - return "${LOCAL_IMAGE_STATUS:-0}" - fi - if [[ "${1:-}" == "pull" ]]; then - printf 'DOCKER_PULL %s\n' "$2" - return "${PULL_STATUS:-0}" - fi - if [[ "${1:-}" == "ps" ]]; then - return 0 - fi - if [[ "${1:-}" == "run" ]]; then - printf 'DOCKER_RUN %s\n' "$*" - return 0 - fi - if [[ "${1:-}" == "exec" || "${1:-}" == "stop" ]]; then - return 0 - fi - echo "Unexpected docker command: $*" >&2 - return 1 -} - -sleep() { - return 0 -} - -export TEST_REVISION -export -f interfold docker sleep - -CASE_OUTPUT="" -CASE_STATUS=0 - -run_case() { - local local_image_status="$1" - local pull_status="$2" - local image_repository="${3:-}" - local start_args=() - if (( $# > 3 )); then - start_args=("${@:4}") - fi - local directory - - directory=$(mktemp -d "$TEST_PARENT/e3-support-test.XXXXXX") - TEST_DIRECTORIES+=("$directory") - - set +e - CASE_OUTPUT=$( - cd "$directory" || exit 1 - # Keep each case independent from credentials and support settings in the parent process. - # GitHub Actions defines PRIVATE_KEY for other jobs in this workflow. - unset RISC0_DEV_MODE RPC_URL PRIVATE_KEY PINATA_JWT IPFS_GATEWAY_URL PROGRAM_URL - unset BOUNDLESS_ONCHAIN BOUNDLESS_MIN_PRICE_ETH BOUNDLESS_MAX_PRICE_ETH - unset BOUNDLESS_TIMEOUT_SECS BOUNDLESS_LOCK_TIMEOUT_SECS BOUNDLESS_RAMP_UP_SECS - unset BOUNDLESS_LOCK_COLLATERAL_ZKC - unset BOUNDLESS_INPUT_ENCODING - if [[ -n "${TEST_INPUT_ENCODING:-}" ]]; then - export BOUNDLESS_INPUT_ENCODING="$TEST_INPUT_ENCODING" - fi - export LOCAL_IMAGE_STATUS="$local_image_status" - export PULL_STATUS="$pull_status" - if [[ -n "$image_repository" ]]; then - export E3_SUPPORT_IMAGE_REPOSITORY="$image_repository" - else - unset E3_SUPPORT_IMAGE_REPOSITORY - fi - if (( ${#start_args[@]} > 0 )); then - bash "$START_SCRIPT" --risc0-dev-mode false "${start_args[@]}" 2>&1 - else - bash "$START_SCRIPT" --risc0-dev-mode false 2>&1 - fi - ) - CASE_STATUS=$? - set -e -} - -assert_contains() { - local expected="$1" - if [[ "$CASE_OUTPUT" != *"$expected"* ]]; then - echo "Expected output to contain: $expected" >&2 - echo "$CASE_OUTPUT" >&2 - exit 1 - fi -} - -assert_not_contains() { - local unexpected="$1" - if [[ "$CASE_OUTPUT" == *"$unexpected"* ]]; then - echo "Expected output not to contain: $unexpected" >&2 - echo "$CASE_OUTPUT" >&2 - exit 1 - fi -} - -run_case 0 0 -[[ "$CASE_STATUS" -eq 0 ]] -assert_not_contains "DOCKER_PULL" -assert_contains "DOCKER_RUN" -assert_contains "ghcr.io/theinterfold/e3-support:$TEST_REVISION" - -run_case 1 0 -[[ "$CASE_STATUS" -eq 0 ]] -assert_contains "DOCKER_PULL ghcr.io/theinterfold/e3-support:$TEST_REVISION" -assert_contains "DOCKER_RUN" - -run_case 1 1 -[[ "$CASE_STATUS" -ne 0 ]] -assert_contains "Support image ghcr.io/theinterfold/e3-support:$TEST_REVISION is unavailable" -assert_not_contains "DOCKER_RUN" - -run_case 0 0 "registry.example/e3-support" -[[ "$CASE_STATUS" -eq 0 ]] -assert_contains "registry.example/e3-support:$TEST_REVISION" - -run_case 0 0 "" \ - --ipfs-gateway-url https://dedicated.example \ - --boundless-min-price-eth 0.0001 \ - --boundless-max-price-eth 0.004 \ - --boundless-timeout-secs 2700 \ - --boundless-lock-timeout-secs 1200 \ - --boundless-ramp-up-secs 300 \ - --boundless-lock-collateral-zkc 3.5 -[[ "$CASE_STATUS" -eq 0 ]] -assert_contains "--env IPFS_GATEWAY_URL" -assert_contains "--env BOUNDLESS_MIN_PRICE_ETH" -assert_contains "--env BOUNDLESS_MAX_PRICE_ETH" -assert_contains "--env BOUNDLESS_TIMEOUT_SECS" -assert_contains "--env BOUNDLESS_LOCK_TIMEOUT_SECS" -assert_contains "--env BOUNDLESS_RAMP_UP_SECS" -assert_contains "--env BOUNDLESS_LOCK_COLLATERAL_ZKC" -assert_not_contains "--env BOUNDLESS_INPUT_ENCODING" - -TEST_INPUT_ENCODING=risc0-serde run_case 0 0 -[[ "$CASE_STATUS" -eq 0 ]] -assert_contains "--env BOUNDLESS_INPUT_ENCODING" -assert_not_contains "--env BOUNDLESS_INPUT_ENCODING=risc0-serde" - -run_case 0 0 "" \ - --rpc-url https://rpc.example \ - --private-key credential-that-must-not-appear \ - --pinata-jwt token-that-must-not-appear -[[ "$CASE_STATUS" -eq 0 ]] -assert_contains "--env RPC_URL" -assert_contains "--env PRIVATE_KEY" -assert_contains "--env PINATA_JWT" -assert_not_contains "credential-that-must-not-appear" -assert_not_contains "token-that-must-not-appear" - -UPLOAD_DIRECTORY=$(mktemp -d "$TEST_PARENT/e3-support-test.XXXXXX") -TEST_DIRECTORIES+=("$UPLOAD_DIRECTORY") -PROGRAM_DIRECTORY="$UPLOAD_DIRECTORY/target/riscv-guest/methods/guests/riscv32im-risc0-zkvm-elf/release" -mkdir -p "$PROGRAM_DIRECTORY" -printf 'cached-program' > "$PROGRAM_DIRECTORY/program.bin" -sha256sum "$PROGRAM_DIRECTORY/program.bin" | awk '{print $1}' > "$UPLOAD_DIRECTORY/target/.program_hash" -printf 'https://gateway.pinata.cloud/ipfs/bafytestcid\n' > "$UPLOAD_DIRECTORY/target/.program_url" -( - cd "$UPLOAD_DIRECTORY" - bash "$REPOSITORY_ROOT/crates/support/scripts/container/upload.sh" \ - --pinata-jwt test-jwt \ - --ipfs-gateway-url https://dedicated.example/ -) -[[ "$(cat "$UPLOAD_DIRECTORY/target/.program_url")" == "https://dedicated.example/ipfs/bafytestcid" ]] - -echo "Support image container tests passed." diff --git a/crates/support/Cargo.lock b/crates/support/Cargo.lock index 8f693c2053..aedeb71480 100644 --- a/crates/support/Cargo.lock +++ b/crates/support/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-core", "futures-sink", @@ -29,8 +29,8 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "base64 0.22.1", - "bitflags 2.10.0", + "base64", + "bitflags", "brotli", "bytes", "bytestring", @@ -49,7 +49,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.2", + "rand 0.9.5", "sha1", "smallvec", "tokio", @@ -251,115 +251,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "alloy" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae62e633fa48b4190af5e841eb05179841bb8b713945103291e2c0867037c0d1" -dependencies = [ - "alloy-consensus", - "alloy-contract", - "alloy-core", - "alloy-eips", - "alloy-network", - "alloy-node-bindings", - "alloy-provider", - "alloy-rpc-client", - "alloy-rpc-types", - "alloy-serde", - "alloy-signer", - "alloy-signer-local", - "alloy-transport", - "alloy-transport-http", - "alloy-trie", -] - -[[package]] -name = "alloy-chains" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc32535569185cbcb6ad5fa64d989a47bccb9a08e27284b1f2a3ccf16e6d010" -dependencies = [ - "alloy-primitives", - "num_enum", - "serde", - "strum", -] - -[[package]] -name = "alloy-consensus" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b151e38e42f1586a01369ec52a6934702731d07e8509a7307331b09f6c46dc" -dependencies = [ - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "alloy-trie", - "alloy-tx-macros", - "auto_impl", - "c-kzg", - "derive_more", - "either", - "k256", - "once_cell", - "rand 0.8.6", - "secp256k1", - "serde", - "serde_json", - "serde_with", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-consensus-any" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2d5e8668ef6215efdb7dcca6f22277b4e483a5650e05f5de22b2350971f4b8" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-contract" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630288cf4f3a34a8c6bc75c03dce1dbd47833138f65f37d53a1661eafc96b83f" -dependencies = [ - "alloy-consensus", - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", - "alloy-sol-types", - "alloy-transport", - "futures", - "futures-util", - "serde_json", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-core" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d47400608fc869727ad81dba058d55f97b29ad8b5c5256d9598523df8f356ab6" -dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-types", -] - [[package]] name = "alloy-dyn-abi" version = "1.4.1" @@ -376,90 +267,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "alloy-eip2124" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "crc", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-eip2930" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "serde", -] - -[[package]] -name = "alloy-eip7702" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-eips" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5434834adaf64fa20a6fb90877bc1d33214c41b055cc49f82189c98614368cc" -dependencies = [ - "alloy-eip2124", - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "auto_impl", - "c-kzg", - "derive_more", - "either", - "serde", - "serde_with", - "sha2", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-genesis" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919a8471cfbed7bcd8cf1197a57dda583ce0e10c6385f6ff4e8b41304b223392" -dependencies = [ - "alloy-eips", - "alloy-primitives", - "alloy-serde", - "alloy-trie", - "serde", -] - -[[package]] -name = "alloy-hardforks" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165210652f71dfc094b051602bafd691f506c54050a174b1cba18fb5ef706a3" -dependencies = [ - "alloy-chains", - "alloy-eip2124", - "alloy-primitives", - "auto_impl", - "dyn-clone", -] - [[package]] name = "alloy-json-abi" version = "1.4.1" @@ -472,81 +279,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "alloy-json-rpc" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c69f6c9c68a1287c9d5ff903d0010726934de0dac10989be37b75a29190d55" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "http 1.4.0", - "serde", - "serde_json", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "alloy-network" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf2ae05219e73e0979cb2cf55612aafbab191d130f203079805eaf881cca58" -dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-types-any", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", - "alloy-sol-types", - "async-trait", - "auto_impl", - "derive_more", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-network-primitives" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58f4f345cef483eab7374f2b6056973c7419ffe8ad35e994b7a7f5d8e0c7ba4" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-node-bindings" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61321a0dbc084c2c9f2b07aa34f10db7ac80065c01721e567e5426d882c73de6" -dependencies = [ - "alloy-genesis", - "alloy-hardforks", - "alloy-network", - "alloy-primitives", - "alloy-signer", - "alloy-signer-local", - "k256", - "rand 0.8.6", - "serde_json", - "tempfile", - "thiserror 2.0.18", - "tracing", - "url", -] - [[package]] name = "alloy-primitives" version = "1.4.1" @@ -560,13 +292,13 @@ dependencies = [ "derive_more", "foldhash 0.2.0", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.9.2", + "rand 0.9.5", "ruint", "rustc-hash", "serde", @@ -574,190 +306,16 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "alloy-provider" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de2597751539b1cc8fe4204e5325f9a9ed83fcacfb212018dfcfa7877e76de21" -dependencies = [ - "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", - "alloy-node-bindings", - "alloy-primitives", - "alloy-rpc-client", - "alloy-rpc-types-anvil", - "alloy-rpc-types-eth", - "alloy-signer", - "alloy-sol-types", - "alloy-transport", - "alloy-transport-http", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "either", - "futures", - "futures-utils-wasm", - "lru 0.13.0", - "parking_lot", - "pin-project", - "reqwest", - "serde", - "serde_json", - "thiserror 2.0.18", - "tokio", - "tracing", - "url", - "wasmtimer", -] - [[package]] name = "alloy-rlp" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ - "alloy-rlp-derive", "arrayvec", "bytes", ] -[[package]] -name = "alloy-rlp-derive" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "alloy-rpc-client" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf8eb8be597cfa8c312934d2566ec4516f066d69164f9212d7a148979fdcfd8" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives", - "alloy-transport", - "alloy-transport-http", - "futures", - "pin-project", - "reqwest", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-rpc-types" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339af7336571dd39ae3a15bde08ae6a647e62f75350bd415832640268af92c06" -dependencies = [ - "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-rpc-types-anvil" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d98fb386a462e143f5efa64350860af39950c49e7c0cbdba419c16793116ef" -dependencies = [ - "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-rpc-types-any" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbde0801a32d21c5f111f037bee7e22874836fba7add34ed4a6919932dd7cf23" -dependencies = [ - "alloy-consensus-any", - "alloy-rpc-types-eth", - "alloy-serde", -] - -[[package]] -name = "alloy-rpc-types-eth" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361cd87ead4ba7659bda8127902eda92d17fa7ceb18aba1676f7be10f7222487" -dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "alloy-sol-types", - "itertools 0.14.0", - "serde", - "serde_json", - "serde_with", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-serde" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64600fc6c312b7e0ba76f73a381059af044f4f21f43e07f51f1fa76c868fe302" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-signer" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5772858492b26f780468ae693405f895d6a27dea6e3eab2c36b6217de47c2647" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "either", - "elliptic-curve 0.13.8", - "k256", - "thiserror 2.0.18", -] - -[[package]] -name = "alloy-signer-local" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4195b803d0a992d8dbaab2ca1986fc86533d4bc80967c0cce7668b26ad99ef9" -dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-primitives", - "alloy-signer", - "async-trait", - "k256", - "rand 0.8.6", - "thiserror 2.0.18", -] - [[package]] name = "alloy-sol-macro" version = "1.4.1" @@ -778,11 +336,10 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ - "alloy-json-abi", "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.12.1", + "indexmap", "proc-macro-error2", "proc-macro2", "quote", @@ -797,14 +354,12 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ - "alloy-json-abi", "const-hex", "dunce", "heck", "macro-string", "proc-macro2", "quote", - "serde_json", "syn 2.0.119", "syn-solidity", ] @@ -832,86 +387,10 @@ dependencies = [ ] [[package]] -name = "alloy-transport" -version = "1.0.41" +name = "anstream" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025a940182bddaeb594c26fe3728525ae262d0806fe6a4befdf5d7bc13d54bce" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives", - "auto_impl", - "base64 0.22.1", - "derive_more", - "futures", - "futures-utils-wasm", - "parking_lot", - "serde", - "serde_json", - "thiserror 2.0.18", - "tokio", - "tower", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-transport-http" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5064d1e1e1aabc918b5954e7fb8154c39e77ec6903a581b973198b26628fa" -dependencies = [ - "alloy-json-rpc", - "alloy-transport", - "reqwest", - "serde_json", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-trie" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "arrayvec", - "derive_more", - "nybbles", - "serde", - "smallvec", - "tracing", -] - -[[package]] -name = "alloy-tx-macros" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab54221eccefa254ce9f65b079c097b1796e48c21c7ce358230f8988d75392fb" -dependencies = [ - "darling 0.21.3", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[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 = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse 0.2.7", @@ -1006,41 +485,7 @@ checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" dependencies = [ "ark-ec 0.5.0", "ark-ff 0.5.0", - "ark-r1cs-std", - "ark-std 0.5.0", -] - -[[package]] -name = "ark-crypto-primitives" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" -dependencies = [ - "ahash", - "ark-crypto-primitives-macros", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-snark", "ark-std 0.5.0", - "blake2", - "derivative", - "digest 0.10.7", - "fnv", - "merlin", - "sha2", -] - -[[package]] -name = "ark-crypto-primitives-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", ] [[package]] @@ -1075,7 +520,7 @@ dependencies = [ "fnv", "hashbrown 0.15.5", "itertools 0.13.0", - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", "zeroize", @@ -1092,7 +537,7 @@ dependencies = [ "ark-serialize 0.3.0", "ark-std 0.3.0", "derivative", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version 0.3.3", @@ -1112,7 +557,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version 0.4.1", @@ -1133,7 +578,7 @@ dependencies = [ "digest 0.10.7", "educe", "itertools 0.13.0", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "zeroize", @@ -1175,7 +620,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "quote", "syn 1.0.109", @@ -1187,7 +632,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -1200,28 +645,13 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", "syn 2.0.119", ] -[[package]] -name = "ark-groth16" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e" -dependencies = [ - "ark-crypto-primitives", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-poly 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-std 0.5.0", -] - [[package]] name = "ark-poly" version = "0.4.2" @@ -1250,35 +680,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "ark-r1cs-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" -dependencies = [ - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-relations", - "ark-std 0.5.0", - "educe", - "num-bigint", - "num-integer", - "num-traits", - "tracing", -] - -[[package]] -name = "ark-relations" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" -dependencies = [ - "ark-ff 0.5.0", - "ark-std 0.5.0", - "tracing", - "tracing-subscriber 0.2.25", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -1298,7 +699,7 @@ dependencies = [ "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", ] [[package]] @@ -1311,7 +712,7 @@ dependencies = [ "ark-std 0.5.0", "arrayvec", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", ] [[package]] @@ -1336,18 +737,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "ark-snark" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" -dependencies = [ - "ark-ff 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-std 0.5.0", -] - [[package]] name = "ark-std" version = "0.3.0" @@ -1378,861 +767,117 @@ dependencies = [ "rand 0.8.6", ] -[[package]] -name = "arraydeque" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" - [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "assert-json-diff" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" -dependencies = [ - "serde", - "serde_json", -] [[package]] -name = "async-attributes" +name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "async-executor" -version = "1.13.3" +name = "auto_impl" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] -name = "async-global-executor" -version = "2.4.1" +name = "autocfg" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "async-io" -version = "2.6.0" +name = "backtrace" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ - "autocfg", + "addr2line", "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", ] [[package]] -name = "async-object-pool" -version = "0.1.5" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333c456b97c3f2d50604e8b2624253b7f787208cb72eb75e64b0ad11b221652c" -dependencies = [ - "async-std", -] +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "async-process" -version = "2.5.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" -dependencies = [ - "async-channel 2.5.0", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.4.1", - "futures-lite", - "rustix", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "async-signal" -version = "0.2.13" +name = "base64ct" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix", - "signal-hook-registry", - "slab", - "windows-sys 0.61.2", -] +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] -name = "async-std" -version = "1.13.2" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "async-attributes", - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", + "serde", ] [[package]] -name = "async-stream" -version = "0.3.6" +name = "bit-set" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", + "bit-vec", ] [[package]] -name = "async-stream-impl" -version = "0.3.6" +name = "bit-vec" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] -name = "async-task" -version = "4.7.1" +name = "bitflags" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[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.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-credential-types" -version = "1.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01c9521fa01558f750d183c8c68c81b0155b9d193a4ba7f84c36bd1b6d04a06" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "zeroize", -] - -[[package]] -name = "aws-lc-rs" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "aws-runtime" -version = "1.5.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce527fb7e53ba9626fc47824f25e256250556c40d8f81d27dd92aa38239d632" -dependencies = [ - "aws-credential-types", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "http 0.2.12", - "http-body 0.4.6", - "percent-encoding", - "pin-project-lite", - "tracing", - "uuid", -] - -[[package]] -name = "aws-sdk-s3" -version = "1.109.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6d81b75f8ff78882e70c5909804b44553d56136899fb4015a0a68ecc870e0e" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-checksums", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "bytes", - "fastrand", - "hex", - "hmac", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "lru 0.12.5", - "percent-encoding", - "regex-lite", - "sha2", - "tracing", - "url", -] - -[[package]] -name = "aws-sigv4" -version = "1.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35452ec3f001e1f2f6db107b6373f1f48f05ec63ba2c5c9fa91f07dad32af11" -dependencies = [ - "aws-credential-types", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "crypto-bigint 0.5.5", - "form_urlencoded", - "hex", - "hmac", - "http 0.2.12", - "http 1.4.0", - "p256", - "percent-encoding", - "ring", - "sha2", - "subtle", - "time", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-async" -version = "1.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "127fcfad33b7dfc531141fda7e1c402ac65f88aca5511a4d31e2e3d2cd01ce9c" -dependencies = [ - "futures-util", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "aws-smithy-checksums" -version = "0.63.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95bd108f7b3563598e4dc7b62e1388c9982324a2abd622442167012690184591" -dependencies = [ - "aws-smithy-http", - "aws-smithy-types", - "bytes", - "crc-fast", - "hex", - "http 0.2.12", - "http-body 0.4.6", - "md-5", - "pin-project-lite", - "sha1", - "sha2", - "tracing", -] - -[[package]] -name = "aws-smithy-eventstream" -version = "0.60.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29a304f8319781a39808847efb39561351b1bb76e933da7aa90232673638658" -dependencies = [ - "aws-smithy-types", - "bytes", - "crc32fast", -] - -[[package]] -name = "aws-smithy-http" -version = "0.62.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445d5d720c99eed0b4aa674ed00d835d9b1427dd73e04adaf2f94c6b2d6f9fca" -dependencies = [ - "aws-smithy-eventstream", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", - "futures-util", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "percent-encoding", - "pin-project-lite", - "pin-utils", - "tracing", -] - -[[package]] -name = "aws-smithy-http-client" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623254723e8dfd535f566ee7b2381645f8981da086b5c4aa26c0c41582bb1d2c" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "h2 0.3.27", - "h2 0.4.12", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper 1.8.1", - "hyper-rustls 0.24.2", - "hyper-rustls 0.27.7", - "hyper-util", - "pin-project-lite", - "rustls 0.21.12", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower", - "tracing", -] - -[[package]] -name = "aws-smithy-json" -version = "0.61.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db31f727935fc63c6eeae8b37b438847639ec330a9161ece694efba257e0c54" -dependencies = [ - "aws-smithy-types", -] - -[[package]] -name = "aws-smithy-observability" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1881b1ea6d313f9890710d65c158bdab6fb08c91ea825f74c1c8c357baf4cc" -dependencies = [ - "aws-smithy-runtime-api", -] - -[[package]] -name = "aws-smithy-runtime" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bbe9d018d646b96c7be063dd07987849862b0e6d07c778aad7d93d1be6c1ef0" -dependencies = [ - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-http-client", - "aws-smithy-observability", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "pin-project-lite", - "pin-utils", - "tokio", - "tracing", -] - -[[package]] -name = "aws-smithy-runtime-api" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7204f9fd94749a7c53b26da1b961b4ac36bf070ef1e0b94bb09f79d4f6c193" -dependencies = [ - "aws-smithy-async", - "aws-smithy-types", - "bytes", - "http 0.2.12", - "http 1.4.0", - "pin-project-lite", - "tokio", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-types" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f535879a207fce0db74b679cfc3e91a3159c8144d717d55f5832aea9eef46e" -dependencies = [ - "base64-simd", - "bytes", - "bytes-utils", - "futures-core", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "http-body-util", - "itoa", - "num-integer", - "pin-project-lite", - "pin-utils", - "ryu", - "serde", - "time", - "tokio", - "tokio-util", -] - -[[package]] -name = "aws-smithy-xml" -version = "0.60.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab77cdd036b11056d2a30a7af7b775789fb024bf216acc13884c6c97752ae56" -dependencies = [ - "xmlparser", -] - -[[package]] -name = "aws-types" -version = "1.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d79fb68e3d7fe5d4833ea34dc87d2e97d26d3086cb3da660bb6b1f76d98680b6" -dependencies = [ - "aws-credential-types", - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "rustc_version 0.4.1", - "tracing", -] - -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[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 = "base64-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" -dependencies = [ - "outref", - "vsimd", -] - -[[package]] -name = "base64ct" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" - -[[package]] -name = "basic-cookies" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bd8fd42c16bdb08688243dc5f0cc117a3ca9efeeaba3a345a18a6159ad96f7" -dependencies = [ - "lalrpop", - "lalrpop-util", - "regex", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec 0.8.0", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - -[[package]] -name = "bitcoin-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "bitvec" -version = "1.0.1" +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 = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[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 = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel 2.5.0", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "blst" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" -dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", -] - -[[package]] -name = "bonsai-sdk" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21055e2f49cbbdbfe9f8f96d597c5527b0c6ab7933341fdc2f147180e48a988e" -dependencies = [ - "duplicate", - "maybe-async", - "reqwest", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "borsh" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "boundless-market" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b60977dc05d0a5b092d8fb30c2fe12e7408928ebf83a45117cc240f9e1375d4" -dependencies = [ - "alloy", - "alloy-chains", - "alloy-primitives", - "alloy-sol-types", - "anyhow", - "async-stream", - "async-trait", - "aws-sdk-s3", - "bytemuck", - "chrono", - "clap", - "dashmap", - "derive_builder", - "futures", - "futures-util", - "hex", - "httpmock", - "rand 0.9.2", - "reqwest", - "risc0-aggregation", - "risc0-ethereum-contracts 3.0.1", - "risc0-zkvm", - "rmp-serde", - "serde", - "serde_json", - "sha2", - "siwe", - "tempfile", - "thiserror 2.0.18", - "time", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-subscriber 0.3.20", - "url", - "utoipa", +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]] @@ -2273,20 +918,6 @@ name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] [[package]] name = "byteorder" @@ -2303,16 +934,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bytes-utils" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" -dependencies = [ - "bytes", - "either", -] - [[package]] name = "bytestring" version = "1.5.0" @@ -2322,53 +943,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "c-kzg" -version = "2.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" -dependencies = [ - "blst", - "cc", - "glob", - "hex", - "libc", - "once_cell", - "serde", -] - -[[package]] -name = "camino" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" -dependencies = [ - "serde_core", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.27", - "serde", - "serde_json", - "thiserror 2.0.18", -] - [[package]] name = "cc" version = "1.2.47" @@ -2387,26 +961,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[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.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "clap" version = "4.6.0" @@ -2447,39 +1001,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.18", -] - [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "const-hex" version = "1.17.0" @@ -2539,33 +1066,12 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -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 = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -2575,34 +1081,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc-fast" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ddc2d09feefeee8bd78101665bd8645637828fa9317f9f292496dbbd8c65ff3" -dependencies = [ - "crc", - "digest 0.10.7", - "rand 0.9.2", - "regex", - "rustversion", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -2643,18 +1121,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-bigint" version = "0.5.5" @@ -2677,107 +1143,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", -] - -[[package]] -name = "darling" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.119", -] - -[[package]] -name = "darling_core" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "serde", - "strsim", - "syn 2.0.119", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core 0.20.11", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "darling_macro" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core 0.21.3", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "der" version = "0.7.10" @@ -2785,7 +1150,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", - "pem-rfc7468", "zeroize", ] @@ -2796,7 +1160,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde_core", ] [[package]] @@ -2810,37 +1173,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn 2.0.119", -] - [[package]] name = "derive_more" version = "2.0.1" @@ -2878,51 +1210,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", + "const-oid", + "crypto-common", + "subtle", ] [[package]] @@ -2942,77 +1232,41 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" -[[package]] -name = "docker-generate" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf673e0848ef09fa4aeeba78e681cf651c0c7d35f76ee38cec8e55bc32fa111" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[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 = "duplicate" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e92f10a49176cbffacaedabfaa11d51db1ea0f80a83c26e1873b43cd1742c24" -dependencies = [ - "heck", - "proc-macro2", - "proc-macro2-diagnostics", -] - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - [[package]] name = "e3-bfv-client" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ "anyhow", "e3-fhe-params", "e3-polynomial", "e3-zk-helpers", - "fhe", - "fhe-traits", - "rand 0.9.2", + "fhe 0.4.1", + "fhe-traits 0.4.1", + "rand 0.9.5", "thiserror 1.0.69", ] [[package]] name = "e3-compute-provider" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", "e3-bfv-client", "e3-fhe-params", - "fhe", + "fhe 0.4.1", "hex", "lean-imt", "light-poseidon", - "num-bigint", + "num-bigint 0.4.6", "num-traits", + "openvm-keccak256", "serde", "sha2", "sha3", @@ -3022,17 +1276,16 @@ dependencies = [ [[package]] name = "e3-fhe-params" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ "alloy-dyn-abi", "alloy-primitives", "anyhow", "clap", - "fhe", - "num-bigint", + "fhe 0.4.1", + "num-bigint 0.5.1", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "serde", "thiserror 1.0.69", @@ -3040,10 +1293,9 @@ dependencies = [ [[package]] name = "e3-parity-matrix" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ - "num-bigint", + "num-bigint 0.5.1", "num-traits", "serde", "thiserror 1.0.69", @@ -3051,11 +1303,10 @@ dependencies = [ [[package]] name = "e3-polynomial" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ - "fhe-math", - "num-bigint", + "fhe-math 0.4.1", + "num-bigint 0.5.1", "num-traits", "serde", "thiserror 1.0.69", @@ -3063,13 +1314,11 @@ dependencies = [ [[package]] name = "e3-safe" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "risc0-bigint2", "sha3", "taceo-poseidon2", ] @@ -3096,30 +1345,18 @@ name = "e3-support-host" version = "0.1.0" dependencies = [ "alloy-primitives", - "alloy-signer-local", "alloy-sol-types", "anyhow", "bincode", - "boundless-market", - "bytemuck", - "dotenvy", "e3-compute-provider", - "e3-fhe-params", "e3-support-types", "e3-user-program", - "fhe", - "fhe-traits", - "fhe-util", "hex", - "log", - "methods", - "rand 0.9.2", - "risc0-ethereum-contracts 3.0.0", - "risc0-zkvm", "serde", + "serde_json", + "sha2", + "tempfile", "tokio", - "tracing-subscriber 0.3.20", - "url", ] [[package]] @@ -3141,16 +1378,17 @@ version = "0.1.0" dependencies = [ "e3-compute-provider", "e3-fhe-params", - "fhe", - "fhe-traits", + "fhe 0.2.1", + "fhe-traits 0.2.1", + "openvm-keccak256", + "openvm-sha2", "sha2", "sha3", ] [[package]] name = "e3-zk-helpers" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.19.0-test.2" dependencies = [ "anyhow", "ark-bn254 0.5.0", @@ -3160,16 +1398,16 @@ dependencies = [ "e3-parity-matrix", "e3-polynomial", "e3-safe", - "fhe", - "fhe-math", - "fhe-traits", + "fhe 0.4.1", + "fhe-math 0.4.1", + "fhe-traits 0.4.1", "hex", "itertools 0.14.0", "ndarray", - "num-bigint", + "num-bigint 0.5.1", "num-integer", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rayon", "serde", "serde_json", @@ -3177,31 +1415,18 @@ dependencies = [ "toml", ] -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature 1.6.4", -] - [[package]] name = "ecdsa" version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.7.10", + "der", "digest 0.10.7", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "serdect", - "signature 2.2.0", - "spki 0.7.3", + "elliptic-curve", + "rfc6979", + "signature", + "spki", ] [[package]] @@ -3221,35 +1446,6 @@ name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -dependencies = [ - "serde", -] - -[[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.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest 0.10.7", - "ff 0.12.1", - "generic-array", - "group 0.12.1", - "pkcs8 0.9.0", - "rand_core 0.6.4", - "sec1 0.3.0", - "subtle", - "zeroize", -] [[package]] name = "elliptic-curve" @@ -3257,41 +1453,19 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", + "base16ct", + "crypto-bigint", "digest 0.10.7", - "ff 0.13.1", + "ff", "generic-array", - "group 0.13.0", - "pkcs8 0.10.2", + "group", + "pkcs8", "rand_core 0.6.4", - "sec1 0.7.3", - "serdect", + "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 = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - [[package]] name = "encoding_rs" version = "0.8.35" @@ -3382,36 +1556,9 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" - -[[package]] -name = "event-listener" -version = "2.5.3" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener 5.4.1", - "pin-project-lite", -] +checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f" [[package]] name = "fastrand" @@ -3441,16 +1588,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "ff" version = "0.13.1" @@ -3468,21 +1605,47 @@ source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6db dependencies = [ "bincode", "doc-comment", - "fhe-math", - "fhe-traits", - "fhe-util", + "fhe-math 0.2.1", + "fhe-traits 0.2.1", + "fhe-util 0.2.1", "itertools 0.14.0", "ndarray", - "num-bigint", + "num-bigint 0.4.6", + "num-traits", + "prost", + "prost-build", + "rand 0.9.5", + "rand_chacha 0.9.0", + "rand_distr", + "rayon", + "serde", + "thiserror 2.0.21", + "zeroize", + "zeroize_derive", +] + +[[package]] +name = "fhe" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +dependencies = [ + "bincode", + "doc-comment", + "fhe-math 0.4.1", + "fhe-traits 0.4.1", + "fhe-util 0.4.1", + "itertools 0.15.0", + "ndarray", + "num-bigint 0.5.1", "num-traits", - "prost 0.14.4", + "prost", "prost-build", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_distr", "rayon", "serde", - "thiserror 2.0.18", + "thiserror 2.0.21", "zeroize", "zeroize_derive", ] @@ -3493,22 +1656,46 @@ version = "0.2.1" source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ "ethnum", - "fhe-traits", - "fhe-util", + "fhe-traits 0.2.1", + "fhe-util 0.2.1", "itertools 0.14.0", "ndarray", - "num-bigint", - "num-bigint-dig 0.9.1", + "num-bigint 0.4.6", + "num-bigint-dig", "num-traits", - "prost 0.14.4", + "prost", "prost-build", "pulp", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "serde", "sha2", "tfhe-ntt", - "thiserror 2.0.18", + "thiserror 2.0.21", + "zeroize", +] + +[[package]] +name = "fhe-math" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +dependencies = [ + "ethnum", + "fhe-traits 0.4.1", + "fhe-util 0.4.1", + "itertools 0.15.0", + "ndarray", + "num-bigint 0.5.1", + "num-bigint-dig", + "num-traits", + "prost", + "prost-build", + "pulp", + "rand 0.9.5", + "rand_chacha 0.9.0", + "serde", + "sha2", + "thiserror 2.0.21", "zeroize", ] @@ -3517,7 +1704,15 @@ name = "fhe-traits" version = "0.2.1" source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ - "rand 0.9.2", + "rand 0.9.5", +] + +[[package]] +name = "fhe-traits" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +dependencies = [ + "rand 0.9.5", ] [[package]] @@ -3525,11 +1720,24 @@ name = "fhe-util" version = "0.2.1" source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ - "num-bigint-dig 0.9.1", + "num-bigint-dig", "num-traits", "prime_factorization", "rand 0.8.6", - "rand 0.9.2", + "rand 0.9.5", + "rand_distr", + "rayon", +] + +[[package]] +name = "fhe-util" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +dependencies = [ + "num-bigint-dig", + "num-traits", + "prime_factorization", + "rand 0.9.5", "rand_distr", "rayon", ] @@ -3552,12 +1760,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "fixedbitset" version = "0.5.7" @@ -3598,28 +1800,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "foreign-types-shared", ] [[package]] @@ -3628,12 +1809,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -3643,33 +1818,12 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[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.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -3677,7 +1831,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -3686,47 +1839,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "futures-sink" version = "0.3.31" @@ -3745,24 +1857,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] -[[package]] -name = "futures-utils-wasm" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" - [[package]] name = "generic-array" version = "0.14.9" @@ -3781,60 +1881,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasip2", - "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gloo-timers" -version = "0.3.0" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "cfg-if", + "libc", + "r-efi", + "wasip2", ] [[package]] -name = "group" -version = "0.12.1" +name = "gimli" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "rand_core 0.6.4", - "subtle", -] +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "group" @@ -3842,7 +1909,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff 0.13.1", + "ff", "rand_core 0.6.4", "subtle", ] @@ -3859,7 +1926,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.12.1", + "indexmap", "slab", "tokio", "tokio-util", @@ -3878,19 +1945,13 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.12.1", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.13.2" @@ -3900,12 +1961,6 @@ dependencies = [ "ahash", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.5" @@ -3928,48 +1983,18 @@ dependencies = [ "serde_core", ] -[[package]] -name = "hashlink" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" -dependencies = [ - "hashbrown 0.15.5", -] - [[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.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-conservative" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[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" @@ -4000,17 +2025,6 @@ dependencies = [ "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" @@ -4030,7 +2044,7 @@ dependencies = [ "bytes", "futures-core", "http 1.4.0", - "http-body 1.0.1", + "http-body", "pin-project-lite", ] @@ -4046,58 +2060,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "httpmock" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ec9586ee0910472dec1a1f0f8acf52f0fdde93aea74d70d4a3107b4be0fd5b" -dependencies = [ - "assert-json-diff", - "async-object-pool", - "async-std", - "async-trait", - "base64 0.21.7", - "basic-cookies", - "crossbeam-utils", - "form_urlencoded", - "futures-util", - "hyper 0.14.32", - "lazy_static", - "levenshtein", - "log", - "regex", - "serde", - "serde_json", - "serde_regex", - "similar", - "tokio", - "url", -] - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.8.1" @@ -4110,7 +2072,7 @@ dependencies = [ "futures-core", "h2 0.4.12", "http 1.4.0", - "http-body 1.0.1", + "http-body", "httparse", "itoa", "pin-project-lite", @@ -4120,22 +2082,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.21.12", - "rustls-native-certs 0.6.3", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.7" @@ -4143,15 +2089,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http 1.4.0", - "hyper 1.8.1", + "hyper", "hyper-util", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -4162,7 +2106,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.8.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -4176,14 +2120,14 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-core", "futures-util", "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", @@ -4196,30 +2140,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "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 = "icu_collections" version = "2.1.1" @@ -4301,12 +2221,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "1.1.0" @@ -4354,23 +2268,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "include_bytes_aligned" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" - -[[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.12.1" @@ -4389,7 +2286,7 @@ version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cfg-if", "libc", ] @@ -4427,27 +2324,27 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" dependencies = [ "either", ] @@ -4509,10 +2406,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "ecdsa", + "elliptic-curve", "once_cell", - "serdect", "sha2", ] @@ -4535,84 +2431,12 @@ dependencies = [ "sha3-asm", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set 0.5.3", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph 0.6.5", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - [[package]] name = "language-tags" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" -[[package]] -name = "lazy-regex" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" -dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", -] - -[[package]] -name = "lazy-regex-proc_macros" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.119", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - [[package]] name = "lean-imt" version = "0.1.2" @@ -4622,12 +2446,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "levenshtein" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" - [[package]] name = "libc" version = "0.2.177" @@ -4640,16 +2458,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.10.0", - "libc", -] - [[package]] name = "light-poseidon" version = "0.2.0" @@ -4658,7 +2466,7 @@ checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", - "num-bigint", + "num-bigint 0.4.6", "thiserror 1.0.69", ] @@ -4688,95 +2496,29 @@ dependencies = [ [[package]] name = "local-waker" version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -dependencies = [ - "value-bag", -] - -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.5", -] - -[[package]] -name = "lru" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" -dependencies = [ - "hashbrown 0.15.5", -] - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "macro-string" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] -name = "matchers" -version = "0.2.0" +name = "lock_api" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "regex-automata", + "scopeguard", ] [[package]] -name = "matrixmultiply" -version = "0.3.10" +name = "log" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" -dependencies = [ - "autocfg", - "rawpointer", -] +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] -name = "maybe-async" -version = "0.2.10" +name = "macro-string" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", @@ -4784,13 +2526,13 @@ dependencies = [ ] [[package]] -name = "md-5" -version = "0.10.6" +name = "matrixmultiply" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ - "cfg-if", - "digest 0.10.7", + "autocfg", + "rawpointer", ] [[package]] @@ -4799,62 +2541,12 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.6.4", - "zeroize", -] - -[[package]] -name = "metal" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" -dependencies = [ - "bitflags 2.10.0", - "block", - "core-graphics-types", - "foreign-types 0.5.0", - "log", - "objc", - "paste", -] - -[[package]] -name = "methods" -version = "0.1.0" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "hex", - "risc0-build", - "risc0-build-ethereum", - "risc0-zkp", - "risc0-zkvm", -] - [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -4895,7 +2587,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] @@ -4916,34 +2608,13 @@ dependencies = [ "serde", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "no_std_strings" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "num" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -4960,23 +2631,19 @@ dependencies = [ "num-integer", "num-traits", "rand 0.8.6", - "serde", ] [[package]] -name = "num-bigint-dig" -version = "0.8.6" +name = "num-bigint" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" dependencies = [ - "lazy_static", - "libm", "num-integer", - "num-iter", "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", + "rand 0.9.5", + "rand_core 0.9.3", + "serde", ] [[package]] @@ -4990,7 +2657,7 @@ dependencies = [ "num-iter", "num-traits", "once_cell", - "rand 0.9.2", + "rand 0.9.5", "serde", "smallvec", ] @@ -5037,7 +2704,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -5052,60 +2719,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "nybbles" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" -dependencies = [ - "alloy-rlp", - "cfg-if", - "proptest", - "ruint", - "serde", - "smallvec", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "object" version = "0.37.3" @@ -5133,9 +2746,9 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cfg-if", - "foreign-types 0.3.2", + "foreign-types", "libc", "once_cell", "openssl-macros", @@ -5172,28 +2785,68 @@ dependencies = [ ] [[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] -name = "outref" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +name = "openvm-keccak256" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-keccak256-guest", + "spin", + "tiny-keccak", +] [[package]] -name = "p256" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros", +] + +[[package]] +name = "openvm-sha2" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", + "openvm-sha2-guest", "sha2", ] +[[package]] +name = "openvm-sha2-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -5222,12 +2875,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" version = "0.12.5" @@ -5257,15 +2904,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -5282,60 +2920,15 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset 0.4.2", - "indexmap 2.12.1", -] - [[package]] name = "petgraph" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ - "fixedbitset 0.5.7", + "fixedbitset", "hashbrown 0.15.5", - "indexmap 2.12.1", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "indexmap", ] [[package]] @@ -5350,46 +2943,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der 0.7.10", - "pkcs8 0.10.2", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", -] - [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.10", - "spki 0.7.3", + "der", + "spki", ] [[package]] @@ -5398,20 +2959,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "windows-sys 0.61.2", -] - [[package]] name = "portable-atomic" version = "1.11.1" @@ -5427,18 +2974,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -5463,12 +2998,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "prettyplease" version = "0.2.37" @@ -5541,29 +3070,17 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "version_check", -] - [[package]] name = "proptest" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", - "bitflags 2.10.0", + "bit-set", + "bit-vec", + "bitflags", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -5572,16 +3089,6 @@ dependencies = [ "unarray", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive 0.13.5", -] - [[package]] name = "prost" version = "0.14.4" @@ -5589,7 +3096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", - "prost-derive 0.14.4", + "prost-derive", ] [[package]] @@ -5602,28 +3109,15 @@ dependencies = [ "itertools 0.14.0", "log", "multimap", - "petgraph 0.8.3", + "petgraph", "prettyplease", - "prost 0.14.4", + "prost", "prost-types", "regex", "syn 2.0.119", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "prost-derive" version = "0.14.4" @@ -5643,14 +3137,14 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ - "prost 0.14.4", + "prost", ] [[package]] name = "pulp" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" dependencies = [ "bytemuck", "cfg-if", @@ -5665,9 +3159,9 @@ dependencies = [ [[package]] name = "pulp-wasm-simd-flag" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" [[package]] name = "quick-error" @@ -5675,61 +3169,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.23.35", - "socket2 0.6.1", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" -dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls 0.23.35", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.1", - "tracing", - "windows-sys 0.60.2", -] - [[package]] name = "quote" version = "1.0.47" @@ -5760,14 +3199,13 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", - "serde", ] [[package]] name = "rand" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -5820,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" dependencies = [ "num-traits", - "rand 0.9.2", + "rand 0.9.5", ] [[package]] @@ -5838,7 +3276,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -5879,49 +3317,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 1.0.69", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.18", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "bitflags", ] [[package]] @@ -5965,29 +3361,24 @@ version = "0.12.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", - "futures-channel", "futures-core", - "futures-util", "h2 0.4.12", "http 1.4.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "js-sys", "log", "mime", - "mime_guess", "native-tls", "percent-encoding", "pin-project-lite", - "quinn", - "rustls 0.23.35", "rustls-pki-types", "serde", "serde_json", @@ -5995,28 +3386,13 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.4", - "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", ] [[package]] @@ -6025,305 +3401,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "risc0-aggregation" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37f9050c74d66eb953591e88a60f2d347e99b121e7330eabb0f29c4053d2a36" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "bytemuck", - "hex", - "risc0-binfmt", - "risc0-zkp", - "risc0-zkvm", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "risc0-bigint2" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87f5f7494a2242cead2750b7ce2b8522c1be83dee268479f1c12ed521eaf595" -dependencies = [ - "include_bytes_aligned", - "stability", -] - -[[package]] -name = "risc0-binfmt" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8f97f81bcdead4101bca06469ecef481a2695cd04e7e877b49dea56a7f6f2a" -dependencies = [ - "anyhow", - "borsh", - "bytemuck", - "derive_more", - "elf", - "lazy_static", - "postcard", - "rand 0.9.2", - "risc0-zkp", - "risc0-zkvm-platform", - "ruint", - "semver 1.0.27", - "serde", - "tracing", -] - -[[package]] -name = "risc0-build" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbb512d728e011d03ce0958ca7954624ee13a215bcafd859623b3c63b2a3f60" -dependencies = [ - "anyhow", - "cargo_metadata", - "derive_builder", - "dirs", - "docker-generate", - "hex", - "risc0-binfmt", - "risc0-zkos-v1compat", - "risc0-zkp", - "risc0-zkvm-platform", - "rzup", - "semver 1.0.27", - "serde", - "serde_json", - "stability", - "tempfile", -] - -[[package]] -name = "risc0-build-ethereum" -version = "3.0.0" -source = "git+https://github.com/risc0/risc0-ethereum?tag=v3.0.0#32aa0b6f23ddd02dd93fc71717667606e5c7db86" -dependencies = [ - "anyhow", - "risc0-build", -] - -[[package]] -name = "risc0-circuit-keccak" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f195f865ac1afdc21a172d7756fdcc21be18e13eb01d78d3d7f2b128fa881ba" -dependencies = [ - "anyhow", - "bytemuck", - "paste", - "risc0-binfmt", - "risc0-circuit-recursion", - "risc0-core", - "risc0-zkp", - "tracing", -] - -[[package]] -name = "risc0-circuit-recursion" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca8f15c8abc0fd8c097aa7459879110334d191c63dd51d4c28881c4a497279e" -dependencies = [ - "anyhow", - "bytemuck", - "hex", - "metal", - "risc0-core", - "risc0-zkp", - "tracing", -] - -[[package]] -name = "risc0-circuit-rv32im" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1b0689f4a270a2f247b04397ebb431b8f64fe5170e98ee4f9d71bd04825205" -dependencies = [ - "anyhow", - "bit-vec 0.8.0", - "bytemuck", - "derive_more", - "paste", - "risc0-binfmt", - "risc0-core", - "risc0-zkp", - "serde", - "tracing", -] - -[[package]] -name = "risc0-core" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" -dependencies = [ - "bytemuck", - "rand_core 0.9.3", -] - -[[package]] -name = "risc0-ethereum-contracts" -version = "3.0.0" -source = "git+https://github.com/risc0/risc0-ethereum?tag=v3.0.0#32aa0b6f23ddd02dd93fc71717667606e5c7db86" -dependencies = [ - "alloy", - "alloy-sol-types", - "anyhow", - "cfg-if", - "risc0-zkvm", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "risc0-ethereum-contracts" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a604f09f459f456fd9ef4919c6efcaa6a787a6f9ffcd76cfc81eae1860584a1" -dependencies = [ - "alloy", - "alloy-primitives", - "alloy-sol-types", - "anyhow", - "cfg-if", - "hex", - "risc0-aggregation", - "risc0-zkvm", - "serde", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "risc0-groth16" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "724285dc79604abfb2d40feaefe3e335420a6b293511661f77d6af62f1f5fae9" -dependencies = [ - "anyhow", - "ark-bn254 0.5.0", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-groth16", - "ark-serialize 0.5.0", - "bytemuck", - "hex", - "num-bigint", - "num-traits", - "risc0-binfmt", - "risc0-zkp", - "serde", -] - -[[package]] -name = "risc0-zkos-v1compat" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf1f35f2ef61d8d86fdd06288c11d2f3bbf08f1af66b24ca0a1976ecbf324a1" -dependencies = [ - "include_bytes_aligned", - "no_std_strings", - "risc0-zkvm-platform", -] - -[[package]] -name = "risc0-zkp" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb6bf356f469bb8744f72a07a37134c5812c1d55d6271bba80e87bdb7a58c8e" -dependencies = [ - "anyhow", - "blake2", - "borsh", - "bytemuck", - "cfg-if", - "digest 0.10.7", - "hex", - "hex-literal", - "metal", - "paste", - "rand_core 0.9.3", - "risc0-core", - "risc0-zkvm-platform", - "serde", - "sha2", - "stability", - "tracing", -] - -[[package]] -name = "risc0-zkvm" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcce11648a9ff60b8e7af2f0ce7fbf8d25275ab6d414cc91b9da69ee75bc978" -dependencies = [ - "anyhow", - "bincode", - "bonsai-sdk", - "borsh", - "bytemuck", - "bytes", - "derive_more", - "hex", - "lazy-regex", - "prost 0.13.5", - "risc0-binfmt", - "risc0-build", - "risc0-circuit-keccak", - "risc0-circuit-recursion", - "risc0-circuit-rv32im", - "risc0-core", - "risc0-groth16", - "risc0-zkos-v1compat", - "risc0-zkp", - "risc0-zkvm-platform", - "rrs-lib", - "rzup", - "semver 1.0.27", - "serde", - "sha2", - "stability", - "tempfile", - "tracing", + "hmac", + "subtle", ] [[package]] -name = "risc0-zkvm-platform" -version = "2.2.1" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "bytemuck", + "cc", "cfg-if", "getrandom 0.2.16", - "getrandom 0.3.4", - "libm", - "num_enum", - "paste", - "stability", + "libc", + "untrusted", + "windows-sys 0.52.0", ] [[package]] @@ -6336,58 +3429,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rmp" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - -[[package]] -name = "rrs-lib" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" -dependencies = [ - "downcast-rs", - "paste", -] - -[[package]] -name = "rsa" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" -dependencies = [ - "const-oid", - "digest 0.10.7", - "num-bigint-dig 0.8.6", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8 0.10.2", - "rand_core 0.6.4", - "signature 2.2.0", - "spki 0.7.3", - "subtle", - "zeroize", -] - [[package]] name = "ruint" version = "1.17.0" @@ -6398,18 +3439,17 @@ dependencies = [ "ark-ff 0.3.0", "ark-ff 0.4.2", "ark-ff 0.5.0", - "borsh", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", "parity-scale-codec", "primitive-types", "proptest", "rand 0.8.6", - "rand 0.9.2", + "rand 0.9.5", "rlp", "ruint-macro", "serde_core", @@ -6465,100 +3505,41 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ - "aws-lc-rs", "once_cell", - "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework 2.11.1", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework 3.5.1", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pki-types" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ - "web-time", "zeroize", ] -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ - "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -6588,34 +3569,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "rzup" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2aed296f203fa64bcb4b52069356dd86d6ec578593985b919b6995bee1f0ae" -dependencies = [ - "hex", - "rsa", - "semver 1.0.27", - "serde", - "serde_with", - "sha2", - "strum", - "tempfile", - "thiserror 2.0.18", - "toml", - "yaml-rust2", -] - -[[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 = "schannel" version = "0.1.28" @@ -6625,117 +3578,34 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "pkcs8 0.9.0", - "subtle", - "zeroize", -] - [[package]] name = "sec1" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct 0.2.0", - "der 0.7.10", + "base16ct", + "der", "generic-array", - "pkcs8 0.10.2", - "serdect", + "pkcs8", "subtle", "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.6", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.1", + "bitflags", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", @@ -6765,10 +3635,6 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] [[package]] name = "semver-parser" @@ -6822,16 +3688,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_regex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" -dependencies = [ - "regex", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.9" @@ -6853,48 +3709,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.12.1", - "schemars 0.9.0", - "schemars 1.1.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" -dependencies = [ - "darling 0.21.3", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "serdect" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" -dependencies = [ - "base16ct 0.2.0", - "serde", -] - [[package]] name = "sha1" version = "0.10.6" @@ -6937,15 +3751,6 @@ dependencies = [ "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" @@ -6961,16 +3766,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - [[package]] name = "signature" version = "2.2.0" @@ -6987,35 +3782,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "similar" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "siwe" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95bdefc0eedf06440b27092fbfe33f2cb493ad6a3423aa12cfe7f2aac44bd618" -dependencies = [ - "hex", - "http 1.4.0", - "iri-string", - "k256", - "rand 0.8.6", - "serde", - "sha3", - "thiserror 1.0.69", - "time", -] - [[package]] name = "slab" version = "0.4.11" @@ -7027,9 +3793,6 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] [[package]] name = "socket2" @@ -7053,38 +3816,18 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.6.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" [[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.10", -] - -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.119", +dependencies = [ + "base64ct", + "der", ] [[package]] @@ -7099,42 +3842,22 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" -dependencies = [ - "strum_macros", -] - [[package]] name = "strum_macros" -version = "0.27.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2", "quote", + "rustversion", "syn 2.0.119", ] @@ -7166,6 +3889,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn-solidity" version = "1.4.1" @@ -7204,8 +3938,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", + "bitflags", + "core-foundation", "system-configuration-sys", ] @@ -7228,7 +3962,7 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "ark-std 0.5.0", - "num-bigint", + "num-bigint 0.4.6", "num-traits", ] @@ -7251,17 +3985,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - [[package]] name = "tfhe-ntt" version = "0.7.1" @@ -7284,11 +4007,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.21", ] [[package]] @@ -7304,31 +4027,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", + "syn 3.0.6", ] [[package]] @@ -7381,21 +4086,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -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.46.1" @@ -7437,50 +4127,14 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" -dependencies = [ - "futures-util", - "log", - "native-tls", + "rustls", "tokio", - "tokio-native-tls", - "tungstenite", ] [[package]] @@ -7532,7 +4186,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.12.1", + "indexmap", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -7546,7 +4200,7 @@ version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.12.1", + "indexmap", "toml_datetime 0.7.3", "toml_parser", "winnow", @@ -7588,11 +4242,11 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-util", "http 1.4.0", - "http-body 1.0.1", + "http-body", "iri-string", "pin-project-lite", "tower", @@ -7642,45 +4296,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", - "valuable", -] - -[[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.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -7689,25 +4304,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "native-tls", - "rand 0.8.6", - "sha1", - "thiserror 1.0.69", - "utf-8", -] - [[package]] name = "typenum" version = "1.19.0" @@ -7738,12 +4334,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - [[package]] name = "unicode-ident" version = "1.0.22" @@ -7773,12 +4363,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -7791,51 +4375,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "utoipa" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" -dependencies = [ - "indexmap 2.12.1", - "serde", - "serde_json", - "utoipa-gen", -] - -[[package]] -name = "utoipa-gen" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - [[package]] name = "vcpkg" version = "0.2.15" @@ -7848,12 +4393,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - [[package]] name = "wait-timeout" version = "0.2.1" @@ -7863,16 +4402,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -7955,33 +4484,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasmtimer" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" -dependencies = [ - "futures", - "js-sys", - "parking_lot", - "pin-utils", - "slab", - "wasm-bindgen", -] - [[package]] name = "web-sys" version = "0.3.82" @@ -7992,91 +4494,6 @@ dependencies = [ "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 = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" -dependencies = [ - "rustls-pki-types", -] - -[[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.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "windows-link" version = "0.2.1" @@ -8298,23 +4715,6 @@ dependencies = [ "tap", ] -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - -[[package]] -name = "yaml-rust2" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "yoke" version = "0.8.1" @@ -8381,18 +4781,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", diff --git a/crates/support/Cargo.toml b/crates/support/Cargo.toml index 1a364e3328..297176eef4 100644 --- a/crates/support/Cargo.toml +++ b/crates/support/Cargo.toml @@ -1,21 +1,20 @@ [workspace] resolver = "3" -msrv = "1.91.1" -members = ["app", "host", "methods", "types"] -exclude = ["methods/guest"] +members = ["app", "host", "types", "program"] +exclude = ["openvm/guest", "openvm/prover"] [workspace.package] version = "0.1.0" edition = "2021" +rust-version = "1.91.1" [workspace.dependencies] e3-support-app = { path = "./app" } e3-support-host = { path = "./host" } e3-user-program = { path = "./program" } e3-support-types = { path = "./types" } -e3-fhe-params = { git = "https://github.com/theinterfold/interfold", rev = "5668f4c9ee0992aeb05b320eaa3b998a6c32e525" } +e3-fhe-params = { path = "../fhe-params" } -methods = { path = "./methods" } alloy-primitives = { version = "1.3", default-features = false, features = [ "rlp", "serde", @@ -31,44 +30,18 @@ env_logger = "=0.11.8" hex = { version = "=0.4.3" } log = { version = "=0.4.27" } reqwest = { version = "=0.12.22", features = ["json"] } -risc0-build = { version = "=3.0.3", features = ["docker"] } -risc0-build-ethereum = { git = "https://github.com/risc0/risc0-ethereum", tag = "v3.0.0" } -risc0-ethereum-contracts = { git = "https://github.com/risc0/risc0-ethereum", tag = "v3.0.0" } -risc0-zkvm = { version = "=3.0.3" } -risc0-zkp = { version = "=3.0.2", default-features = false } serde = { version = "1.0", features = ["derive", "std"] } serde_json = "=1.0.145" sha2 = "=0.10.9" sha3 = "=0.10.8" -# The Interfold revision must match for all Interfold dependencies in this workspace. -# -# The Interfold crates below are pinned by revision rather than by path because this workspace is -# excluded from the root workspace on purpose (see the root Cargo.toml): a client must be able to -# build crates/support on its own, and the RISC Zero Docker build context root is crates/support, -# so anything outside that directory is unreachable from the guest build. -# -# The pin therefore decides which compute-provider code the guest runs, and moving it changes the -# image ID. Bump it only together with a reproducible rebuild of -# crates/support/contracts/ImageID.sol and a complete provenance manifest. -# -# Why this revision: 5668f4c9 contains the compute-input binding, secure-parameter fixes, -# shared-parameter path, and accelerated SAFE commitment path that the guest must run. -# -# It replaces c2097da6, the scope commit of the 2026-08-17 Zenith protocol audit. Sitting at the -# audited baseline read as the conservative choice and was not: the audit covered six Solidity -# files and no Rust at all, so crates/compute-provider and the guest were outside its scope, and -# outside the mitigation review at c64bcfb8 as well. See packages/interfold-contracts/audits/README.md. -# Holding the old audit pin bought reproducibility rather than assurance while excluding real fixes -# to the code the guest runs. The revision remains content-addressed even though a permanent main -# commit retains it; a movable branch or tag is not an acceptable guest dependency. +# Build this workspace from the repository root to include the guest source dependencies. fhe = { package = "fhe", git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } -e3-compute-provider = { git = "https://github.com/theinterfold/interfold", rev = "5668f4c9ee0992aeb05b320eaa3b998a6c32e525" } +e3-compute-provider = { path = "../compute-provider" } tokio = { version = "=1.46.1", features = ["full"] } rand = { version = "=0.9.2" } tracing-subscriber = { version = "=0.3.20", features = ["env-filter"] } -boundless-market = { version = "=1.1.0" } url = { version = "=2.5.4" } dotenvy = { version = "=0.15.7" } diff --git a/crates/support/Dockerfile b/crates/support/Dockerfile index 53aa28420c..7100121dac 100644 --- a/crates/support/Dockerfile +++ b/crates/support/Dockerfile @@ -1,69 +1,14 @@ ARG RUST_VERSION=1.91.1 -ARG RISC0_VERSION=3.0.3 -ARG RISC0_TOOLCHAIN=1.91.1 -ARG SKIP_SOLIDITY=0 -FROM rust:${RUST_VERSION}-slim-bookworm AS base-dev - -ENV CARGO_HOME=/usr/local/cargo -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - pkg-config \ - git \ - libssl-dev \ - curl \ - sudo \ - ca-certificates \ - protobuf-compiler && \ - rm -rf /var/lib/apt/lists/* - -# Create user -ENV USERNAME=devuser -ARG USER_UID=1000 -ARG USER_GID=1000 - -RUN groupadd --gid $USER_GID $USERNAME \ - && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ - && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ - && chmod 0440 /etc/sudoers.d/$USERNAME - -USER $USERNAME -WORKDIR /home/$USERNAME - -ENV SHELL=/bin/bash - -ENV PATH="/home/${USERNAME}/.risc0/bin:${PATH}" -RUN curl -L https://risczero.com/install | bash - -# Re-declared inside the stage. An ARG before the first FROM is only in scope for FROM lines, so -# these expanded to nothing here and `rzup install` silently took its own default — the opposite of -# what pinning them is for. A bare ARG picks up the default declared at the top of the file. -ARG RISC0_VERSION -ARG RISC0_TOOLCHAIN - -# Empty is the failure this guards against, and it is silent: `rzup install rust` with no version -# installs whatever rzup considers current, and the image still builds. -RUN set -eu; \ - : "${RISC0_TOOLCHAIN:?RISC0_TOOLCHAIN is empty; declare the ARG inside this stage}"; \ - : "${RISC0_VERSION:?RISC0_VERSION is empty; declare the ARG inside this stage}" - -RUN rzup install rust ${RISC0_TOOLCHAIN} -RUN rzup install r0vm ${RISC0_VERSION} -RUN rzup install cargo-risczero ${RISC0_VERSION} - -RUN sudo ln -sf "$(readlink -f "$(command -v r0vm)")" /usr/local/bin/r0vm && \ - test -x /usr/local/bin/r0vm -ENV RISC0_SERVER_PATH=/usr/local/bin/r0vm - -ENV PATH="/home/${USERNAME}/.foundry/bin:${PATH}" -RUN curl -L https://foundry.paradigm.xyz | bash -RUN foundryup - -COPY . /app - -RUN sudo chown -R $USERNAME:$USERNAME /app - +FROM rust:${RUST_VERSION}-slim-bookworm +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential cmake pkg-config git libssl-dev ca-certificates protobuf-compiler \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app - -CMD ["/bin/bash"] +# The support workspace uses repository-local guest dependencies. +COPY Cargo.toml Cargo.lock rust-toolchain.toml ./ +COPY crates ./crates +COPY examples/CRISP/program ./examples/CRISP/program +RUN cargo build --locked --release --manifest-path crates/support/Cargo.toml -p e3-support-app +# Mount a separately built OpenVM worker, its configuration, and its proving artifacts. +ENV OPENVM_BIND_ADDR=0.0.0.0:13151 +CMD ["./crates/support/target/release/e3-support-app"] diff --git a/crates/support/README.md b/crates/support/README.md index 066d49b7de..014c89bbcd 100644 --- a/crates/support/README.md +++ b/crates/support/README.md @@ -1,373 +1,102 @@ -# E3 Support — RISC Zero + Boundless Compute Provider +# OpenVM compute service -Docker-based compute provider that runs FHE homomorphic computations and proves them via -[Boundless](https://boundless.network) (a decentralized ZK proving market). The container exposes an -HTTP API on port 13151 that receives encrypted ciphertexts, runs the FHE computation, submits a -proof request to Boundless, and sends the result back via webhook callback. +The support service runs the Secure Process and returns a verified OpenVM receipt. It runs on the +operator's machine. It does not require a proving-market account, payment wallet, or program upload. -```mermaid -graph TD - subgraph N["e3-support-scripts"] - A["interfold program start"] - AA["./.interfold/support/ctl/start"] - A --> AA - end - M["E3 instigator (CRISP server)"] --"POST /run_compute (with callback_url)"--> D - D --"webhook callback"--> O["callback server (CRISP) publishes on-chain"] - AA --listen on port 13151--> D - subgraph C["e3-support (container)"] - D["app (actix HTTP server)"] - E["host (Boundless client)"] - F["types (WebhookPayload)"] - G["compute-provider (FHE + merkle)"] - H["methods (risc0 build)"] - I["guest (risc0 zkVM program)"] - J["user-program (fhe_processor)"] +The normal path is: - D --> E - D --> F - D --> G - E --> H - E --> G - E --> J - H --> I - I --> G - I --> J - end -``` - -## Architecture - -- **`app/`** — Actix HTTP server (`e3-support-app` binary). Exposes `/run_compute` (POST) and - `/health` (GET/HEAD). -- **`host/`** — Boundless SDK integration. Builds the client, submits proof requests, waits for - fulfillment. -- **`types/`** — Shared request, webhook, proof-domain, guest-input, and journal types. -- **`methods/`** — RISC Zero build crate. Compiles the guest program. -- **`methods/guest/`** — The RISC Zero zkVM guest program. Runs `fhe_processor` (homomorphic - ciphertext summation) and commits the domain-bound `ComputeJournal`. -- **`program/`** — The FHE processor (`fhe_processor`): sums BFV ciphertexts homomorphically. - -## Webhook Payload Format - -The callback server receives a tagged-enum JSON payload: - -**Success:** - -```json -{ - "status": "completed", - "e3_id": "123", - "ciphertext": "0x...", - "ciphertext_commitment": "0x...", - "proof": "0x..." -} -``` - -**Failure:** +`CRISP server → POST /run_compute → OpenVM worker → HTTP callback → ciphertext publication` -```json -{ "status": "failed", "e3_id": "123", "error": "Computation failed: ..." } -``` +The program server does not submit the publication transaction. CRISP verifies the callback, +publishes the ciphertext to its data-availability layer, and submits the resulting reference. +Both the protocol verifier and the application verifier must accept the compute proof. -This matches the format expected by CRISP and `E3ProgramServer` in `crates/program-server`. +## Components ---- +- `app/`: the HTTP service, request admission, computation scheduling, and callback delivery. +- `host/`: native computation, worker execution, journal comparison, and proof-envelope encoding. +- `types/`: requests, callbacks, proof domains, guest inputs, and the nine-word journal. +- `program/`: the canonical CRISP processor and input policy, shared with the native host. +- `openvm/guest/`: the guest that proves the computation and reveals the journal digest. +- `openvm/prover/`: the separate worker that generates and verifies the EVM proof. -## Full E3 Flow — Step by Step +These are isolated Cargo workspaces. Use the root `pnpm openvm` commands to select them. -### Prerequisites +## Configure and start -1. **RISC Zero toolchain** — `rzup install` -2. **Docker** — for the support container -3. **Pinata account** — for IPFS program uploads (get a JWT at https://pinata.cloud) -4. **Boundless wallet** — an Ethereum private key with ETH for gas and the request payment on the - Boundless-supported chain. The prover supplies the ZKC collateral. -5. **Interfold CLI** — `cargo install --locked --path ./crates/cli --bin interfold -f` -6. **An Interfold project** — `interfold init `, then work from that directory. The steps - below run against a project, not against a checkout of this repository. Without one, - `interfold program compile` exits with `Configuration file not found`, because `interfold init` - is what writes `.interfold/support/ctl`, the scripts every `program` subcommand shells out to. +Follow [the OpenVM build instructions](openvm/README.md) to prepare the worker, guest, proving +keys, verifier artifact, and worker configuration. -### Step 1: Configure `interfold.config.yaml` +Set these deployment-local absolute paths in `interfold.config.yaml`: ```yaml program: dev: false - risc0: - risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev (fake proofs) - boundless: - rpc_url: 'https://sepolia.base.org' # or your RPC URL - private_key: '${PRIVATE_KEY}' # use env var for secrets! - pinata_jwt: '${PINATA_JWT}' - # Use a dedicated public gateway. Boundless provers download the complete input from it. - ipfs_gateway_url: 'https://your-gateway.mypinata.cloud' - program_url: 'https://your-gateway.mypinata.cloud/ipfs/Qm...' # after upload (Step 3) - onchain: true - # Optional auction parameters with their built-in defaults: - # min_price_eth: 0.00005 - # max_price_eth: 0.004 - # timeout_secs: 28800 - # lock_timeout_secs: 14400 - # ramp_up_secs: 7200 - # lock_collateral_zkc: 100.0 -``` - -### Step 2: Compile the RISC Zero Guest Program - -```bash -interfold program compile + openvm: + repository: ${OPENVM_REPOSITORY} + prover_bin: ${OPENVM_PROVER_BIN} + prover_config: ${OPENVM_PROVER_CONFIG} ``` -This builds the guest ELF binary inside the Docker container. Output goes to -`./target/riscv-guest/methods/guests/riscv32im-risc0-zkvm-elf/release/program.bin`. - -The guest runs the `fhe_processor` and `policy` from `crates/support/program`, which -`methods/guest/Cargo.toml` names as `e3-user-program`. Another E3 program needs a guest built -against its own crate of that name: the policy decides the input-tree leaf, and a leaf that differs -from the one the program's contract built produces a root the round cannot publish. - -### Changing the guest, and the pin that decides which code it runs - -The guest does **not** compile `crates/compute-provider` from this tree. `crates/support` is a -separate Cargo workspace, excluded from the root one on purpose so a client can build it -independently, and it reads `e3-compute-provider` and `e3-fhe-params` through a git pin to a -published revision (`crates/support/Cargo.toml`, `crates/support/methods/guest/Cargo.toml`). - -A change to `crates/compute-provider` therefore has no effect on the guest until that pin moves, and -the pin can only move to a pushed commit. Moving it changes the image ID, and -`Risc0BfvCiphertextVerifier.imageId` is immutable — so a guest change is a redeployment, not a -patch. - -The order matters: - -1. Merge the change to `crates/compute-provider`, then push. -2. Bump every Interfold pin to the merge commit. There are three, and they must all name the same - revision — the guest and host workspaces have to compile the same sources: - - `e3-fhe-params` in `crates/support/Cargo.toml` - - `e3-compute-provider` in `crates/support/Cargo.toml` - - `e3-compute-provider` in `crates/support/methods/guest/Cargo.toml` - - Then refresh both lockfiles (`crates/support/Cargo.lock` and - `crates/support/methods/guest/Cargo.lock`). The Docker guest build passes `--locked`, so a - lockfile one line behind its manifest stops the reproducible build before it starts. - -3. Update the `crates/support` call sites that track the crate's API — the compiler will point at - them, since they built against the old revision until now. -4. Rebuild the guest against the pinned code with `RISC0_USE_DOCKER=1`. The pinned Docker builder - regenerates `crates/support/contracts/ImageID.sol`; ordinary native builds deliberately do not - touch that production trust anchor. -5. Redeploy `Risc0BfvCiphertextVerifier`, and every E3 program that stores its own image ID. - -Skipping step 4 leaves a deployed verifier that accepts a guest that does not match this tree. The -provenance manifest records the committed image ID and compares it with a deployed verifier. It does -not rebuild the guest. Therefore, this build order is mandatory. See -`docs/pages/build/e3-program/verify-compute-provider.mdx` for the complete verification procedure. - -### Step 3: Upload Program to IPFS (Pinata) - -```bash -interfold program upload -``` - -This uploads the compiled guest ELF to Pinata IPFS and caches the resulting URL at -`./target/.program_url`. Copy this URL into your `interfold.config.yaml` as -`program.risc0.boundless.program_url` to avoid re-uploading the program at runtime. - -The host sends raw bincode input by default. For a deployed guest that expects the older RISC Zero -byte-vector format, set `BOUNDLESS_INPUT_ENCODING=risc0-serde` before `interfold program start`. -This setting requires `program_url` and applies only to Boundless. The embedded guest keeps raw -bincode input. Verify that the external guest image ID matches both deployed verifiers before use. -An encoding change does not change the guest image ID or the journal format. - -To test an external guest without submitting a proof request, set `RISC0_TEST_GUEST` to its binary -path and `RISC0_TEST_INPUT` to a raw bincode `ComputeGuestInput` file. Set `RISC0_TEST_IMAGE_ID` to -the expected image ID without `0x`, and select `BOUNDLESS_INPUT_ENCODING`. Then run: +Then run: ```sh -cargo test --manifest-path crates/support/Cargo.toml -p e3-support-host --lib \ - configured_guest_matches_host_journal --locked -- --ignored --nocapture -``` - -Run this command from the repository root. It checks the image ID and compares every guest journal -field with the host computation. It does not generate a proof or submit a transaction. - -### Step 4: Deploy Interfold Contracts + Start Ciphernodes - -```bash -# Deploy contracts to local Hardhat / testnet -pnpm evm:deploy - -# Start the ciphernode network -interfold start -``` - -This boots the ciphernodes, which listen for E3 requests, perform DKG, and await ciphertext outputs. - -### Step 5: Start the Program Server (Boundless-backed) - -```bash +interfold program compile interfold program start ``` -This starts the Docker container that runs `e3-support-app` on port 13151. The `risc0_dev_mode` -value selects the proving backend, as shown in Step 1. `0` submits proofs to the Boundless market. -`1` returns fake proofs. The default is `1` when the field is unset. A Boundless request with -missing credentials fails instead of using dev mode. - -### Step 6: Submit an E3 Request - -The E3 request is submitted on-chain by the instigator (e.g., CRISP coordination server): - -```solidity -// On-chain: Interfold.request(params) -interfold.request(IInterfold.E3RequestParams({ - committeeSize: IInterfold.CommitteeSize.Minimum, - inputWindow: [start, end], - e3Program: IE3Program(crispProgramAddress), - paramSet: paramSetIndex, // registered via setParamSet - computeProviderParams: "", - customParams: encodedRoundConfig, // CRISPProgram decodes seven values from this - expectedFeeToken: IERC20(feeTokenAddress), - expectedCryptoConfigId: cryptoConfigId, - maxFee: maxFee -})); -``` - -This triggers: +`compile` builds the native HTTP service. It does not regenerate the guest or proving keys. +`start` validates the configured worker and artifacts before it accepts requests. Missing +configuration is an error. There is no automatic unproved fallback. -1. Payment of the quoted fee in the active fee token -2. Committee selection via sortition -3. DKG (C0-C5 proofs) → committee public key published in bounded Ethereum event chunks -4. Stage → `KeyPublished` +The CRISP reference guest uses CRISP's input policy. Another E3 program needs a host and guest +built against its own processor and policy. The contract, host, and guest must derive the same +input leaves, selected inputs, parameter hash, and journal. -### Step 7: Encrypt Inputs & Submit to Compute Provider +## HTTP interface -The instigator encrypts data under the committee's aggregate public key. The application publishes -large ciphertexts to its configured data-availability layer before it commits their references on -Ethereum. The compute request still POSTs the retrieved bytes to the program server: - -```bash -curl -X POST http://localhost:13151/run_compute \ - -H "Content-Type: application/json" \ - -d '{ - "e3_id": "1", - "chain_id": 31337, - "interfold_address": "0x1111111111111111111111111111111111111111", - "encryption_scheme_id": "0x...", - "committee_public_key_hash": "0x...", - "params": "0x...", - "ciphertext_inputs": [["0x...", 0], ["0x...", 1]], - "callback_url": "http://host.local:4000/state/add-result" - }' -``` - -The program server: - -1. Returns `{"status":"processing","e3_id":"1"}` immediately -2. Runs FHE computation (homomorphic sum) locally → ciphertext output -3. Submits proof request to Boundless market -4. Waits for a prover to fulfill the request -5. Sends webhook callback with - `{"status":"completed","e3_id":"1","ciphertext":"0x...","ciphertext_commitment":"0x...","proof":"0x..."}` - -Steps 3 and 4 belong to the Boundless path that Step 1 configures. With `risc0_dev_mode: 1` the -server runs the same computation and returns a fake proof instead. - -### Step 8: Webhook Handler Publishes On-Chain - -The callback server publishes the aggregate ciphertext to the configured data-availability layer, -waits for its Ethereum-verifiable receipt, and calls: - -```solidity -interfold.publishCiphertextOutput(e3Id, encodedOutputReference); -``` +The listener defaults to `127.0.0.1:13151`. Set `OPENVM_BIND_ADDR` to change it. -The proof binds nine values. Five identify the context: the chain, the Interfold contract, the E3, -the encryption scheme, and the committee key hash. Four come from the computation: the output hash, -the SAFE commitment, the parameter hash, and the input root. The protocol verifier checks these -fields before the E3 program verifier. Both checks must pass before the E3 can remain in -`CiphertextReady`. +- `GET /health` and `HEAD /health` report service health. +- `POST /run_compute` accepts the existing program-server request. It contains the full E3 domain, + BFV parameters, indexed ciphertexts, published commitments and metadata, and a callback URL. +- The immediate response acknowledges processing. It is not a proof or a publication receipt. -### Step 9: Decryption & Completion +A successful callback contains `status: "completed"`, `e3_id`, `ciphertext`, +`ciphertext_commitment`, and `proof`. Binary fields use hexadecimal encoding. +A failed callback contains `status: "failed"`, `e3_id`, and `error`. -The ciphernodes detect `CiphertextReady`, produce decryption shares (C6 proofs), the active -aggregator combines them (C7 proof), and publishes the plaintext on-chain. Stage → `Complete`, -rewards distributed. +The proof envelope contains the seal, parameter hash, and input root. The seal contains the +Halo2 proof and all nine journal words. See [the receipt format](openvm/README.md#contract-migration). ---- +The service admits one active computation by default. Jobs are in memory. A service restart can lose an +accepted job. Operators must reconcile interrupted jobs and failed callback delivery. +Use authenticated admission control and a deployment-specific callback policy. Do not expose +the unrestricted listener to the Internet. -## Boundless Offer Parameters +## Container -`build_offer()` reads these environment variables. Defaults: +From the repository root: -| Parameter | Env Var | Default | Description | -| ------------ | ------------------------------- | --------- | ----------------------------- | -| Min price | `BOUNDLESS_MIN_PRICE_ETH` | `0.00005` | Starting price in ETH | -| Max price | `BOUNDLESS_MAX_PRICE_ETH` | `0.004` | Maximum auction price in ETH | -| Timeout | `BOUNDLESS_TIMEOUT_SECS` | `28800` | Total request lifetime (sec) | -| Lock timeout | `BOUNDLESS_LOCK_TIMEOUT_SECS` | `14400` | Primary prover deadline (sec) | -| Ramp-up | `BOUNDLESS_RAMP_UP_SECS` | `7200` | Price ramp-up period (sec) | -| Collateral | `BOUNDLESS_LOCK_COLLATERAL_ZKC` | `100.0` | ZKC locked per request | - -Set the matching fields under `program.risc0.boundless` to change these values. The CLI sends each -configured field through the support launcher to the container. Leave a field unset to use its -default. The secure CRISP rehearsal used about 29 billion cycles. On September 3, 2026, a six-month -sample contained 421 fulfilled Boundless orders between 20 and 40 billion cycles. Their median -accepted price was about `0.00136 ETH`, and 95% were accepted by about `0.00379 ETH`. `0.002 ETH` -covered about 82% of the sample, while `0.004 ETH` covered about 96%. All comparable orders in the -sample used `100 ZKC` collateral. The `0.004 ETH` default is an auction ceiling, not the expected -charge. The requester pays the accepted lock price. This sample does not guarantee future -acceptance. Review the ceiling before using a materially larger guest or input set. - ---- - -## Building the Container - -```bash -# Local build -./scripts/build.sh - -# With push to registry -./scripts/build.sh --push -``` - -The CI workflow builds the container for applicable pull requests without publishing it. A manual CI -run on `main` publishes the nine-character commit tag and the `main` tag. - -Each release publishes the version tag, the nine-character commit tag, and the `latest` tag. The CLI -uses its embedded commit tag. The CLI pulls the matching image when the image is not available -locally. - -Set `E3_SUPPORT_IMAGE_REPOSITORY` to use an authorized mirror instead of the default GitHub -Container Registry repository. - -## Development - -To develop inside the container (with RISC Zero toolchain available): - -```bash -./scripts/dev.sh +```sh +bash crates/support/scripts/build.sh ``` -Inside the container: +The container builds the native service, not the GPU worker. Mount the worker, its runtime +libraries, its configuration, and its proving artifacts. Provide GPU access for a CUDA worker. +Keep the service and worker on a compatible operating system. The CLI runs the configured local +service directly and does not pull a container image. -```bash -cargo build --locked -cargo run --bin e3-support-app -``` - -## Testing +## Verification -```bash -cargo test --manifest-path host/Cargo.toml +```sh +pnpm openvm service-test +pnpm openvm contract-test ``` -NOTE: This is outside of the main workspace because it needs to be run within its own context in -order to isolate risc0. - -NOTE: We are attempting to isolate risc0 - it is anticipated that we will have to use feature flags -to tidy this up so that we can compile more of the code and enable rust-analyzer to work outside of -the risc0 environment for this project. +Use `pnpm openvm proof-test` for an externally supplied real proof. +Use `pnpm openvm service-e2e` for the live HTTP workflow on an isolated local chain. +[The OpenVM instructions](openvm/README.md#checks) list the required inputs and test boundaries. -**NOTE: currently this is an open relay which is a known issue** +An explicit `program.dev: true` selects an unproved development runner. That runner is not +OpenVM and cannot pass a real receipt verifier. diff --git a/crates/support/app/Cargo.toml b/crates/support/app/Cargo.toml index 2a14b4dd3f..c1312abd97 100644 --- a/crates/support/app/Cargo.toml +++ b/crates/support/app/Cargo.toml @@ -17,8 +17,3 @@ hex.workspace = true [dependencies.e3-support-host] workspace = true -optional = true - -[features] -default = ["risc0"] -risc0 = ["e3-support-host"] diff --git a/crates/support/app/src/main.rs b/crates/support/app/src/main.rs index 0dc9f04386..7137451ca1 100644 --- a/crates/support/app/src/main.rs +++ b/crates/support/app/src/main.rs @@ -100,34 +100,9 @@ async fn run_computation_async( }) .await?; - match result { - Ok((boundless_output, ciphertext)) => match boundless_output { - e3_support_host::BoundlessOutput::Success { result, seal, .. } => { - anyhow::ensure!( - result.ciphertext_commitment.len() == 32, - "Boundless journal ciphertext commitment must be 32 bytes" - ); - println!( - "have result from computation! seal len: {}, ciphertext len: {}, commitment len: {}", - seal.len(), - ciphertext.len(), - result.ciphertext_commitment.len() - ); - let proof = e3_support_host::encode_compute_proof(&seal, &result) - .map_err(|error| anyhow::anyhow!("invalid compute proof: {error:?}"))?; - Ok((proof, ciphertext, result.ciphertext_commitment)) - } - e3_support_host::BoundlessOutput::Error { error } => { - Err(anyhow::anyhow!("Boundless request failed: {}", error)) - } - }, - Err(e3_support_host::ComputeError::BoundlessFailed(msg)) => { - Err(anyhow::anyhow!("Boundless request failed: {}", msg)) - } - Err(e3_support_host::ComputeError::Other(msg)) => { - Err(anyhow::anyhow!("Computation error: {}", msg)) - } - } + let (output, ciphertext) = result?; + let proof = e3_support_host::encode_compute_proof(&output.seal, &output.result)?; + Ok((proof, ciphertext, output.result.ciphertext_commitment)) } async fn process_computation_background( @@ -172,8 +147,8 @@ async fn process_computation_background( /// Whether callbacks to addresses only reachable from inside the deployment are permitted. /// -/// Off by default. Local development legitimately posts to a host on the same machine, so there has -/// to be a way in, but it must be a deliberate one rather than the default. +/// Off by default for private networks and internal hostnames. Loopback callbacks are permitted +/// separately so an isolated local CRISP server can receive results. fn allow_private_callbacks() -> bool { matches!( std::env::var("ALLOW_PRIVATE_CALLBACKS") @@ -213,11 +188,8 @@ fn validate_callback_url(raw: &str) -> ActixResult<()> { return Ok(()); } - // Loopback is deliberately NOT treated as internal. The escalation worth guarding is reaching - // hosts the caller cannot reach itself — cloud metadata, RFC1918 services, .internal names. - // Loopback is the machine this server already runs on, and it is how every local deployment - // posts its webhook. Note this runs BEFORE the localhost -> host.local rewrite below, so that - // rewrite is unaffected by `.local` remaining blocked. + // Allow loopback callbacks for local deployments. Block private networks, cloud metadata, + // and internal hostnames unless the operator explicitly enables private callbacks. fn v4_is_internal(ip: Ipv4Addr) -> bool { if ip.is_loopback() { return false; @@ -261,7 +233,7 @@ fn validate_callback_url(raw: &str) -> ActixResult<()> { if internal { return Err(actix_web::error::ErrorBadRequest( - "callback_url must not point at a private, loopback or link-local address; \ + "callback_url must not point at a private or link-local address; \ set ALLOW_PRIVATE_CALLBACKS=1 to permit it for local development", )); } @@ -273,7 +245,7 @@ fn validate_callback_url(raw: &str) -> ActixResult<()> { /// /// Proving is the most expensive thing this process does, and the handler previously spawned one /// detached task per request with nothing bounding them: a caller could open as many as they liked -/// and exhaust CPU, memory, blocking workers and Boundless submissions together. One at a time by +/// and exhaust CPU, memory, and GPU workers together. One at a time by /// default, because a single proof already saturates the machine. fn max_concurrent_computations() -> usize { std::env::var("MAX_CONCURRENT_COMPUTATIONS") @@ -406,11 +378,6 @@ async fn handle_compute(req: web::Json) -> ActixResult ActixResult { #[actix_web::main] async fn main() -> anyhow::Result<()> { env_logger::init(); - let bind_addr = "0.0.0.0:13151"; + e3_support_host::check_configuration()?; + let bind_addr = std::env::var("OPENVM_BIND_ADDR").unwrap_or_else(|_| "127.0.0.1:13151".into()); + let request_limit: usize = std::env::var("OPENVM_MAX_REQUEST_BYTES") + .unwrap_or_else(|_| (128 * 1024 * 1024).to_string()) + .parse()?; + anyhow::ensure!( + request_limit > 0 && request_limit <= 1024 * 1024 * 1024, + "OPENVM_MAX_REQUEST_BYTES must be between 1 byte and 1 GiB" + ); let server = HttpServer::new(move || { App::new() + .app_data(web::JsonConfig::default().limit(request_limit)) .wrap(Logger::default()) .route("/run_compute", web::post().to(handle_compute)) .route("/health", web::get().to(handle_health_check)) .route("/health", web::head().to(handle_health_check)) }) - .bind(bind_addr)?; + .bind(&bind_addr)?; println!("🚀 FHE Compute Service listening on http://{}", bind_addr); server.run().await.map_err(Into::into) } diff --git a/crates/support/host/Cargo.toml b/crates/support/host/Cargo.toml index 8315f5bedd..ed4c0869cb 100644 --- a/crates/support/host/Cargo.toml +++ b/crates/support/host/Cargo.toml @@ -5,29 +5,19 @@ edition = { workspace = true } [dependencies] bincode = { workspace = true } -bytemuck = { workspace = true } serde = { workspace = true } alloy-primitives = { workspace = true } alloy-sol-types = { workspace = true } -alloy-signer-local = { workspace = true } anyhow = { workspace = true } -log = { workspace = true } -methods = { workspace = true } -risc0-ethereum-contracts = { workspace = true } -risc0-zkvm = { workspace = true } tokio = { workspace = true } e3-compute-provider = { workspace = true } e3-support-types = { workspace = true } -fhe = { workspace = true } -fhe-traits = { workspace = true } -fhe-util = { workspace = true } e3-user-program = { workspace = true } -rand = { workspace = true } -tracing-subscriber = { workspace = true } -boundless-market = { workspace = true } -url = { workspace = true } -dotenvy = { workspace = true } -e3-fhe-params = { workspace = true, features = ["abi-encoding"] } + +tempfile = "3" +sha2.workspace = true +serde_json.workspace = true +hex.workspace = true [dev-dependencies] hex = { workspace = true } diff --git a/crates/support/host/README.md b/crates/support/host/README.md index afa5583b4b..dfbe2e9e96 100644 --- a/crates/support/host/README.md +++ b/crates/support/host/README.md @@ -1,4 +1,11 @@ -# Risc0 Host +# OpenVM host -Exposes a function to run the computation found in `e3_user_program::fhe_processor` whilst also -generating a risc0 proof assuming `risc0_dev_mode` is _not_ set. +The host runs the canonical processor and policy to derive the ciphertext and nine-word journal. It +passes the input and expected journal to a separate OpenVM worker. + +The worker must generate a real EVM proof, verify the application identity and journal, and write a +verified seal. The host returns the ciphertext, SAFE commitment, and compute-proof envelope to the +HTTP service. A worker error fails the job. + +See [the service instructions](../README.md) and +[the OpenVM build instructions](../openvm/README.md). diff --git a/crates/support/host/src/bin/profile_risc0.rs b/crates/support/host/src/bin/profile_risc0.rs deleted file mode 100644 index 611bd56b57..0000000000 --- a/crates/support/host/src/bin/profile_risc0.rs +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use e3_compute_provider::FHEInputs; -use e3_fhe_params::{build_bfv_params_from_set_arc, encode_bfv_params, BfvPreset}; -use e3_support_host::run_risc0_compute; -use e3_support_types::ComputeDomain; -use fhe::bfv::{Encoding, Plaintext, PublicKey, SecretKey}; -use fhe_traits::{FheEncoder, FheEncrypter, Serialize}; -use rand::rng; - -fn main() { - println!("Starting RISC0 profiling with mock ciphertexts..."); - - // BFV preset is configurable via env var, defaulting to insecure threshold - // for fast profiling. Set BFV_PRESET to one of: - // INSECURE_THRESHOLD_BFV_512 | INSECURE_DKG_BFV_512 | - // SECURE_THRESHOLD_BFV_8192 | SECURE_DKG_BFV_8192 - let param_set: BfvPreset = match std::env::var("BFV_PRESET").ok().as_deref() { - Some("INSECURE_DKG_512") => BfvPreset::InsecureDkg512, - Some("SECURE_THRESHOLD_BFV_8192") => BfvPreset::SecureThreshold8192, - Some("SECURE_DKG_8192") => BfvPreset::SecureDkg8192, - Some(other) => { - eprintln!( - "Warning: unknown BFV_PRESET={}, using default InsecureThreshold512", - other - ); - BfvPreset::InsecureThreshold512 - } - None => BfvPreset::InsecureThreshold512, - }; - println!("Using BFV preset: {:?}", param_set); - - let params = build_bfv_params_from_set_arc(param_set.into()); - - println!( - "Generated BFV parameters: degree={}, plaintext_modulus={}", - params.degree(), - params.plaintext() - ); - - // Generate keys - let mut rng = rng(); - let secret_key = SecretKey::random(¶ms, &mut rng); - let public_key = PublicKey::new(&secret_key, &mut rng); - - println!("Generated secret and public keys"); - - // Encrypt values 1, 2, 3 - let values = vec![1u64, 2u64, 3u64]; - let mut ciphertexts = Vec::new(); - - for (idx, value) in values.iter().enumerate() { - let plaintext = Plaintext::try_encode(&[*value], Encoding::poly(), ¶ms) - .expect("Failed to encode plaintext"); - let ciphertext = public_key - .try_encrypt(&plaintext, &mut rng) - .expect("Failed to encrypt"); - - ciphertexts.push((ciphertext.to_bytes(), idx as u64)); - println!("Encrypted value {} as ciphertext {}", value, idx); - } - - // Encode params to bytes - let params_bytes = encode_bfv_params(¶ms); - println!("Encoded params to {} bytes", params_bytes.len()); - - // Create FHEInputs - let fhe_inputs = FHEInputs { - ciphertexts, - params: params_bytes, - }; - - println!("Calling run_risc0_compute..."); - - // Call run_risc0_compute - let domain = ComputeDomain::new( - 31_337, - "0x1111111111111111111111111111111111111111", - "0", - &[0x22; 32], - &[0x33; 32], - ) - .expect("invalid compute domain"); - // No published data: this profiles the default policy, which is what the template program uses. - match run_risc0_compute(fhe_inputs, domain, Vec::new()) { - Ok((output, ciphertext)) => { - println!("Success! RISC0 computation completed"); - println!("Output result: {:?}", output.result); - println!("Output bytes length: {}", output.bytes.len()); - println!("Seal length: {}", output.seal.len()); - println!("Processed ciphertext length: {}", ciphertext.len()); - } - Err(e) => { - eprintln!("Error during RISC0 computation: {:?}", e); - std::process::exit(1); - } - } -} diff --git a/crates/support/host/src/lib.rs b/crates/support/host/src/lib.rs index 5abf1f77ef..0c4fd47d46 100644 --- a/crates/support/host/src/lib.rs +++ b/crates/support/host/src/lib.rs @@ -1,596 +1,95 @@ // SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -use alloy_primitives::{ - utils::{parse_ether, parse_units}, - Bytes, B256, -}; -use alloy_signer_local::PrivateKeySigner; +use alloy_primitives::{Bytes, B256}; use alloy_sol_types::SolValue; -use anyhow::{Context, Error, Result}; -use bincode::serialize; -use boundless_market::{ - client::ClientError, - contracts::{boundless_market::MarketError, FulfillmentData}, - request_builder::OfferParams, - storage::storage_provider_from_env, - Client, -}; -use e3_compute_provider::{ - ComputeInput, ComputeManager, ComputeProvider, FHEInputs, InputPolicy, PublishedData, -}; +use anyhow::{ensure, Context, Result}; +use e3_compute_provider::{ComputeInput, FHEInputs, PublishedData}; use e3_support_types::{ComputeDomain, ComputeGuestInput, ComputeJournal}; -use e3_user_program::{fhe_processor, policy}; -use methods::PROGRAM_ELF; -use risc0_ethereum_contracts::groth16; -use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, VerifierContext}; -use std::error::Error as _; -use std::time::{Duration, Instant}; -use url::Url; +use std::{env, fs, path::PathBuf, process::Command}; -pub struct BoundlessProvider { - domain: ComputeDomain, -} - -#[derive(Debug, Clone)] -pub enum BoundlessOutput { - Success { - result: ComputeJournal, - bytes: Vec, - seal: Vec, - }, - Error { - error: String, - }, -} - -#[derive(Debug)] -pub enum ComputeError { - BoundlessFailed(String), - Other(String), -} - -/// The compute provider has its own error type; this one is the host's public surface. -/// -/// Flattened to a string rather than re-exported so the host's callers do not have to depend on -/// the provider crate to match on a failure. -impl From for ComputeError { - fn from(error: e3_compute_provider::ComputeError) -> Self { - ComputeError::Other(error.to_string()) - } -} - -impl ComputeProvider for BoundlessProvider { - type Output = BoundlessOutput; - - fn prove(&self, input: &ComputeInput, policy: InputPolicy) -> Self::Output { - let is_dev_mode = - std::env::var("RISC0_DEV_MODE").unwrap_or_else(|_| "0".to_string()) == "1"; - - if is_dev_mode { - println!("Dev mode: Using fake proof"); - fake_prove(input, &self.domain, policy) - } else { - println!("Using Boundless for proving"); - tokio::runtime::Handle::current().block_on(boundless_prove(input, &self.domain)) - } - } -} - -fn encode_journal(result: &ComputeJournal) -> Result, Error> { - Ok(bytemuck::pod_collect_to_vec(&risc0_zkvm::serde::to_vec( - result, - )?)) -} - -fn encode_guest_input(input: &ComputeGuestInput) -> Result, Error> { - // Boundless passes these bytes directly to guest stdin. A RISC Zero serde wrapper would store - // each bincode byte in a 32-bit word and would add no integrity or decoding guarantee. - serialize(input).context("Failed to serialize guest input") -} - -fn encode_boundless_input( - input: &[u8], - encoding: Option<&str>, - program_url: Option<&str>, -) -> Result> { - match encoding { - None | Some("bincode") => Ok(input.to_vec()), - Some("risc0-serde") => { - anyhow::ensure!( - program_url.is_some_and(|url| !url.is_empty()), - "BOUNDLESS_INPUT_ENCODING=risc0-serde requires PROGRAM_URL for a compatible guest" - ); - // Older deployed guests decode a RISC Zero byte vector before decoding bincode. - Ok(bytemuck::pod_collect_to_vec(&risc0_zkvm::serde::to_vec( - input, - )?)) - } - Some(_) => anyhow::bail!("BOUNDLESS_INPUT_ENCODING must be bincode or risc0-serde"), - } -} - -/// Dev mode: return fake proof without executing -fn fake_prove( - input: &ComputeInput, - domain: &ComputeDomain, - policy: InputPolicy, -) -> BoundlessOutput { - println!("Generating fake proof for dev mode"); - - // Execute the program with the input. The policy is the caller's, so dev mode computes the same - // result the guest would rather than silently falling back to the default. - let processed = match input.process(fhe_processor, policy) { - Ok(processed) => processed, - Err(error) => return to_output_error(Error::from(error)), - }; - - let result = match ComputeJournal::new(domain.clone(), processed) { - Ok(result) => result, - Err(error) => return to_output_error(error), - }; - - let journal_bytes = match encode_journal(&result) { - Ok(bytes) => bytes, - Err(error) => return to_output_error(error), - }; - - BoundlessOutput::Success { - result, - bytes: journal_bytes, - seal: vec![], // No seal in dev mode - } -} - -fn to_output_error(e: E) -> BoundlessOutput { - BoundlessOutput::Error { - error: e.to_string(), - } -} - -/// Read an optional floating-point environment variable. -fn env_opt_f64(key: &str) -> Result> { - match std::env::var(key) { - Ok(value) => Ok(Some( - value - .parse() - .with_context(|| format!("{key} must be a number"))?, - )), - Err(std::env::VarError::NotPresent) => Ok(None), - Err(error) => Err(error).with_context(|| format!("failed to read {key}")), - } -} - -/// Read an optional whole-second environment variable. -fn env_opt_secs(key: &str) -> Result> { - match std::env::var(key) { - Ok(value) => { - Ok(Some(value.parse().with_context(|| { - format!("{key} must be a whole number of seconds") - })?)) - } - Err(std::env::VarError::NotPresent) => Ok(None), - Err(error) => Err(error).with_context(|| format!("failed to read {key}")), - } -} - -const DEFAULT_BOUNDLESS_MIN_PRICE_ETH: &str = "0.00005"; -const DEFAULT_BOUNDLESS_MAX_PRICE_ETH: &str = "0.004"; -const DEFAULT_BOUNDLESS_TIMEOUT_SECS: u64 = 8 * 60 * 60; -const DEFAULT_BOUNDLESS_LOCK_TIMEOUT_SECS: u64 = 4 * 60 * 60; -const DEFAULT_BOUNDLESS_RAMP_UP_SECS: u64 = 2 * 60 * 60; -const DEFAULT_BOUNDLESS_LOCK_COLLATERAL_ZKC: f64 = 100.0; - -/// Build the OfferParams from environment variables, using sensible defaults. -fn build_offer() -> Result { - build_offer_from_values( - env_opt_f64("BOUNDLESS_MIN_PRICE_ETH")?, - env_opt_f64("BOUNDLESS_MAX_PRICE_ETH")?, - env_opt_secs("BOUNDLESS_TIMEOUT_SECS")?, - env_opt_secs("BOUNDLESS_LOCK_TIMEOUT_SECS")?, - env_opt_secs("BOUNDLESS_RAMP_UP_SECS")?, - env_opt_f64("BOUNDLESS_LOCK_COLLATERAL_ZKC")?, - ) -} - -fn build_offer_from_values( - min_price_eth: Option, - max_price_eth: Option, - timeout_secs: Option, - lock_timeout_secs: Option, - ramp_up_secs: Option, - lock_collateral_zkc: Option, -) -> Result { - let min_price = if let Some(value) = min_price_eth { - if value.is_sign_negative() || !value.is_finite() { - anyhow::bail!( - "BOUNDLESS_MIN_PRICE_ETH must be a non-negative number, got: {}", - value - ); - } - parse_ether(&value.to_string()).context("Invalid BOUNDLESS_MIN_PRICE_ETH")? - } else { - parse_ether(DEFAULT_BOUNDLESS_MIN_PRICE_ETH).context("Invalid default min_price")? - }; - let max_price = if let Some(value) = max_price_eth { - if value.is_sign_negative() || !value.is_finite() { - anyhow::bail!( - "BOUNDLESS_MAX_PRICE_ETH must be a non-negative number, got: {}", - value - ); - } - parse_ether(&value.to_string()).context("Invalid BOUNDLESS_MAX_PRICE_ETH")? - } else { - parse_ether(DEFAULT_BOUNDLESS_MAX_PRICE_ETH).context("Invalid default max_price")? - }; - - if min_price > max_price { - anyhow::bail!("BOUNDLESS_MIN_PRICE_ETH must not exceed BOUNDLESS_MAX_PRICE_ETH"); - } - - let timeout = u32::try_from(timeout_secs.unwrap_or(DEFAULT_BOUNDLESS_TIMEOUT_SECS)) - .context("BOUNDLESS_TIMEOUT_SECS exceeds the supported range")?; - let lock_timeout = - u32::try_from(lock_timeout_secs.unwrap_or(DEFAULT_BOUNDLESS_LOCK_TIMEOUT_SECS)) - .context("BOUNDLESS_LOCK_TIMEOUT_SECS exceeds the supported range")?; - let ramp_up = u32::try_from(ramp_up_secs.unwrap_or(DEFAULT_BOUNDLESS_RAMP_UP_SECS)) - .context("BOUNDLESS_RAMP_UP_SECS exceeds the supported range")?; - - if lock_timeout == 0 || lock_timeout >= timeout { - anyhow::bail!("BOUNDLESS_LOCK_TIMEOUT_SECS must be greater than zero and less than BOUNDLESS_TIMEOUT_SECS"); - } - if ramp_up > lock_timeout { - anyhow::bail!("BOUNDLESS_RAMP_UP_SECS must not exceed BOUNDLESS_LOCK_TIMEOUT_SECS"); - } - - let zkc = lock_collateral_zkc.unwrap_or(DEFAULT_BOUNDLESS_LOCK_COLLATERAL_ZKC); - if zkc.is_sign_negative() || !zkc.is_finite() { - anyhow::bail!( - "BOUNDLESS_LOCK_COLLATERAL_ZKC must be a non-negative number, got: {}", - zkc - ); - } - let collateral: alloy_primitives::U256 = parse_units(&format!("{}", zkc), 18) - .context("Invalid BOUNDLESS_LOCK_COLLATERAL_ZKC")? - .into(); - - Ok(OfferParams::builder() - .min_price(min_price) - .max_price(max_price) - .timeout(timeout) - .lock_timeout(lock_timeout) - .ramp_up_period(ramp_up) - .lock_collateral(collateral) - .into()) -} - -async fn boundless_prove(input: &ComputeInput, domain: &ComputeDomain) -> BoundlessOutput { - match boundless_prove_inner(input, domain).await { - Ok(output) => output, - Err(e) => { - // Print the full error chain so the root cause is visible in logs. - eprintln!("✗ Boundless proof request FAILED:"); - eprintln!(" Error: {:#}", e); - let mut source = e.source(); - while let Some(s) = source { - eprintln!(" Caused by: {}", s); - source = s.source(); - } - to_output_error(e) - } - } -} - -async fn boundless_prove_inner( - input: &ComputeInput, - domain: &ComputeDomain, -) -> Result { - println!("Submitting proof request to Boundless..."); - - let rpc_url = std::env::var("RPC_URL") - .context("RPC_URL not set")? - .parse() - .context("Invalid RPC_URL")?; - - let private_key: PrivateKeySigner = std::env::var("PRIVATE_KEY") - .context("PRIVATE_KEY not set")? - .parse() - .context("Invalid PRIVATE_KEY")?; - - let storage_provider = match storage_provider_from_env() { - Ok(provider) => Some(provider), - Err(e) => { - eprintln!("Warning: Failed to get storage provider: {}", e); - None - } - }; - - // Diagnostic: log what we're connecting to (key and API path never logged). - println!( - "Boundless client: caller={}, storage_provider={}", - private_key.address(), - storage_provider.is_some(), - ); - - let client = Client::builder() - .with_rpc_url(rpc_url) - .with_private_key(private_key) - .with_storage_provider(storage_provider) - .build() - .await - .context("Failed to build Boundless client")?; - - let guest_input = ComputeGuestInput { - domain: domain.clone(), - input: input.clone(), - }; - let program_url = std::env::var("PROGRAM_URL").ok(); - let input_encoding = match std::env::var("BOUNDLESS_INPUT_ENCODING") { - Ok(value) => Some(value), - Err(std::env::VarError::NotPresent) => None, - Err(error) => return Err(error).context("Failed to read BOUNDLESS_INPUT_ENCODING"), - }; - let input_bytes = encode_boundless_input( - &encode_guest_input(&guest_input)?, - input_encoding.as_deref(), - program_url.as_deref(), - )?; - let stdin_size = input_bytes.len(); - - let request = if let Some(ref url) = program_url { - println!("Using pre-uploaded program: {}", url); - let parsed_url = url.parse::().context("Failed to parse program URL")?; - - client - .new_request() - .with_program_url(parsed_url) - .context("Failed to create new request")? - .with_stdin(input_bytes) - .with_offer(build_offer()?) - } else { - println!( - "Warning: Uploading {}MB program at runtime", - PROGRAM_ELF.len() / 1_000_000 - ); - client - .new_request() - .with_program(PROGRAM_ELF) - .with_stdin(input_bytes) - .with_offer(build_offer()?) - }; - - let request = request.with_groth16_proof(); - - let onchain = - std::env::var("BOUNDLESS_ONCHAIN").unwrap_or_else(|_| "true".to_string()) == "true"; - - println!( - "Boundless submission: onchain={}, program_url={:?}, stdin_size={}", - onchain, program_url, stdin_size, - ); - - let (request_id, expires_at) = if onchain { - println!("Building request..."); - let proof_request = match client.build_request(request).await { - Ok(r) => { - println!("✓ Request built successfully (id: {:x})", r.id); - r - } - Err(e) => { - eprintln!("✗ Build request FAILED:"); - eprintln!(" Debug: {:?}", e); - eprintln!(" Display: {:#}", e); - let mut source = e.source(); - while let Some(s) = source { - eprintln!(" Caused by: {}", s); - source = s.source(); - } - return Err(anyhow::anyhow!("Failed to build request: {:#}", e)); - } - }; - - println!("Submitting onchain (request id: {:x})...", proof_request.id); - match client.submit_request_onchain(&proof_request).await { - Ok(result) => { - println!("✓ Onchain submission successful"); - result - } - Err(e) => { - eprintln!("✗ Onchain submission FAILED:"); - eprintln!(" Display: {:#}", e); - let mut source = e.source(); - while let Some(s) = source { - eprintln!(" Caused by: {}", s); - source = s.source(); - } - return Err(anyhow::anyhow!("Failed to submit onchain: {:#}", e)); - } - } - } else { - println!("Submitting offchain..."); - match client.submit_offchain(request).await { - Ok(result) => { - println!("✓ Offchain submission successful"); - result - } - Err(e) => { - eprintln!("✗ Offchain submission FAILED:"); - eprintln!(" Error: {:#}", e); - let mut source = e.source(); - while let Some(s) = source { - eprintln!(" Caused by: {}", s); - source = s.source(); - } - return Err(anyhow::anyhow!("Failed to submit offchain: {:#}", e)); - } - } - }; - - println!("Request ID: {:x}, waiting for fulfillment...", request_id); - - let fulfillment = match client - .wait_for_request_fulfillment(request_id, Duration::from_secs(5), expires_at) - .await - { - Ok(fulfillment) => fulfillment, - Err(ClientError::MarketError(MarketError::RequestHasExpired(_))) => { - return Ok(BoundlessOutput::Error { - error: format!( - "Boundless request expired: no prover picked up the request. Request ID: {:x}", - request_id - ), - }); - } - Err(e) => return Err(e).context("Failed to wait for fulfillment")?, - }; - - println!("Proof received from Boundless!"); - let data = fulfillment.data(); - let (_, journal) = match data { - Ok(FulfillmentData::ImageIdAndJournal(image_id, journal)) => (image_id, journal), - _ => { - return Ok(BoundlessOutput::Error { - error: "Invalid fulfillment data".to_string(), - }); - } - }; - - let decoded_journal: ComputeJournal = risc0_zkvm::serde::from_slice(&journal) - .map_err(|e| anyhow::anyhow!("Failed to decode journal: {}", e))?; - - Ok(BoundlessOutput::Success { - result: decoded_journal, - bytes: journal.to_vec(), - seal: fulfillment.seal.to_vec(), - }) -} - -pub struct Risc0Provider { - domain: ComputeDomain, -} - -#[derive(Debug, Clone)] -pub struct Risc0Output { +pub struct OpenVmOutput { pub result: ComputeJournal, - pub bytes: Vec, pub seal: Vec, } -impl ComputeProvider for Risc0Provider { - type Output = Risc0Output; - - fn prove(&self, input: &ComputeInput, _policy: InputPolicy) -> Self::Output { - // The policy is not forwarded: the guest calls the user program's own `policy()`, so - // passing one here would let host and guest disagree about the leaves and the selection. - let guest_input = ComputeGuestInput { - domain: self.domain.clone(), - input: input.clone(), - }; - let encoded_input = encode_guest_input(&guest_input).unwrap(); - let env = ExecutorEnv::builder() - .write_slice(&encoded_input) - .build() - .unwrap(); - - let receipt = default_prover() - .prove_with_ctx( - env, - &VerifierContext::default(), - PROGRAM_ELF, - &ProverOpts::groth16(), - ) - .unwrap() - .receipt; - - let decoded_journal: ComputeJournal = receipt.journal.decode().unwrap(); - - // Check if RISC0_DEV_MODE is set to "1" (dev mode) - // If dev mode: return empty seal (fake proof) - // Otherwise: return real groth16 proof - let is_dev_mode = std::env::var("RISC0_DEV_MODE").unwrap_or_default() == "1"; - - let seal = if is_dev_mode { - println!("RISC0_DEV_MODE=1: Using fake proof (empty seal)"); - vec![] - } else { - println!("RISC0_DEV_MODE=0 or unset: Generating real Groth16 proof"); - groth16::encode(receipt.inner.groth16().unwrap().seal.clone()).unwrap() - }; - - Risc0Output { - result: decoded_journal, - bytes: receipt.journal.bytes.clone(), - seal, - } +/// Reject missing prover configuration before the service accepts work. +pub fn check_configuration() -> Result<()> { + for name in ["OPENVM_PROVER_BIN", "OPENVM_PROVER_CONFIG"] { + let path = PathBuf::from(env::var(name).with_context(|| format!("Set {name}"))?); + ensure!( + path.is_absolute() && path.is_file(), + "{name} must name an existing absolute file path" + ); } + let status = Command::new(env::var("OPENVM_PROVER_BIN")?) + .arg("check") + .arg(env::var("OPENVM_PROVER_CONFIG")?) + .status()?; + ensure!(status.success(), "OpenVM configuration validation failed"); + Ok(()) } pub fn run_compute( params: FHEInputs, domain: ComputeDomain, published: Vec, -) -> std::result::Result<(BoundlessOutput, Vec), ComputeError> { - let boundless_provider = BoundlessProvider { domain }; - - // `with_published` rather than `new`: the policy reads this to rebuild the leaves the E3 - // program's contract built. Passing an empty vec is the same as `new`, which is what a program - // using the default policy wants. - let mut provider = ComputeManager::with_published( - boundless_provider, - params.clone(), - published, - fhe_processor, +) -> Result<(OpenVmOutput, Vec)> { + ensure!( + params.ciphertexts.len() <= 1024, + "The input count exceeds the guest limit" ); - - // Start timer - let start_time = Instant::now(); - - let output = provider.start(policy())?; - - // Capture end time and calculate the duration - let elapsed_time = start_time.elapsed(); - - // Convert the elapsed time to minutes and seconds - let minutes = elapsed_time.as_secs() / 60; - let seconds = elapsed_time.as_secs() % 60; - - println!( - "Prove function execution time: {} minutes and {} seconds", - minutes, seconds + let input = ComputeGuestInput { + domain: domain.clone(), + input: ComputeInput { + fhe_inputs: params, + published, + }, + }; + let (result, ciphertext) = input + .input + .run(e3_user_program::fhe_processor, e3_user_program::policy()) + .map_err(|error| anyhow::anyhow!("{error}"))?; + let journal = ComputeJournal::new(domain, result).map_err(anyhow::Error::msg)?; + let journal_bytes = journal.abi_bytes().map_err(anyhow::Error::msg)?; + let input_bytes = bincode::serialize(&input)?; + ensure!( + input_bytes.len() <= 512 * 1024 * 1024 - 16, + "The input exceeds the guest byte limit" ); - - // Check if the output indicates failure - match &output.0 { - BoundlessOutput::Success { .. } => Ok(output), - BoundlessOutput::Error { error } => Err(ComputeError::BoundlessFailed(error.clone())), - } -} - -pub fn run_risc0_compute( - params: FHEInputs, - domain: ComputeDomain, - published: Vec, -) -> std::result::Result<(Risc0Output, Vec), ComputeError> { - let risc0_provider = Risc0Provider { domain }; - - let mut provider = - ComputeManager::with_published(risc0_provider, params.clone(), published, fhe_processor); - - Ok(provider.start(policy())?) + let job = tempfile::Builder::new() + .prefix("interfold-openvm-") + .tempdir()?; + let input_path = job.path().join("input.bin"); + let journal_path = job.path().join("journal.bin"); + let seal_path = job.path().join("seal.bin"); + fs::write(&input_path, input_bytes)?; + fs::write(&journal_path, journal_bytes)?; + let status = Command::new(env::var("OPENVM_PROVER_BIN").context("Set OPENVM_PROVER_BIN")?) + .arg("prove") + .arg(env::var("OPENVM_PROVER_CONFIG").context("Set OPENVM_PROVER_CONFIG")?) + .arg(&input_path) + .arg(&journal_path) + .arg(&seal_path) + .status() + .context("Cannot start the OpenVM prover")?; + ensure!( + status.success(), + "OpenVM proof generation or verification failed" + ); + let seal = fs::read(seal_path).context("The OpenVM prover did not return a verified seal")?; + ensure!(seal.len() == 2144, "The OpenVM seal has an invalid length"); + Ok(( + OpenVmOutput { + result: journal, + seal, + }, + ciphertext, + )) } -pub fn encode_compute_proof( - seal: &[u8], - result: &ComputeJournal, -) -> std::result::Result, ComputeError> { - if result.params_hash.len() != 32 || result.merkle_root.len() != 32 { - return Err(ComputeError::Other( - "Compute journal context must contain two 32-byte values".to_string(), - )); - } +pub fn encode_compute_proof(seal: &[u8], result: &ComputeJournal) -> Result> { + result.abi_bytes().map_err(anyhow::Error::msg)?; + ensure!(seal.len() == 2144, "The OpenVM seal has an invalid length"); Ok(( Bytes::copy_from_slice(seal), B256::from_slice(&result.params_hash), @@ -602,232 +101,57 @@ pub fn encode_compute_proof( #[cfg(test)] mod tests { use super::*; - use bincode::deserialize; - use risc0_zkvm::sha::{Impl, Sha256}; - - fn risc0_vec32(value: &[u8]) -> Vec { - let mut encoded = Vec::with_capacity(132); - encoded.extend_from_slice(&32_u32.to_le_bytes()); - for byte in value { - encoded.extend_from_slice(&u32::from(*byte).to_le_bytes()); - } - encoded - } - - #[test] - fn boundless_offer_defaults_fit_secure_compute() { - let offer = build_offer_from_values(None, None, None, None, None, None).unwrap(); - - assert_eq!( - offer.min_price, - Some(parse_ether(DEFAULT_BOUNDLESS_MIN_PRICE_ETH).unwrap()) - ); - assert_eq!( - offer.max_price, - Some(parse_ether(DEFAULT_BOUNDLESS_MAX_PRICE_ETH).unwrap()) - ); - assert_eq!(offer.timeout, Some(DEFAULT_BOUNDLESS_TIMEOUT_SECS as u32)); - assert_eq!( - offer.lock_timeout, - Some(DEFAULT_BOUNDLESS_LOCK_TIMEOUT_SECS as u32) - ); - assert_eq!( - offer.ramp_up_period, - Some(DEFAULT_BOUNDLESS_RAMP_UP_SECS as u32) - ); - assert_eq!( - offer.lock_collateral, - Some(parse_units("100", 18).unwrap().into()) - ); - } + use e3_compute_provider::ComputeResult; #[test] - fn boundless_offer_rejects_invalid_deadlines() { - let error = build_offer_from_values(None, None, Some(60), Some(60), None, None) - .expect_err("equal lock and total deadlines must fail"); - - assert!(error - .to_string() - .contains("BOUNDLESS_LOCK_TIMEOUT_SECS must be greater than zero")); - } - - #[test] - fn guest_input_uses_direct_bincode() { - let input = ComputeGuestInput { - domain: ComputeDomain::new( - 31_337, - "0x1111111111111111111111111111111111111111", - "7", - &[0x22; 32], - &[0x33; 32], - ) - .unwrap(), - input: ComputeInput { - fhe_inputs: FHEInputs { - ciphertexts: vec![(vec![0xaa; 32], 0)], - params: vec![0xbb; 16], - }, - published: vec![PublishedData { - commitment: Some([0xcc; 32]), - metadata: vec![0xdd; 25], - }], - }, + fn journal_and_envelope_preserve_all_fields() { + let domain = ComputeDomain { + chain_id: 1, + verifying_contract: [2; 20], + e3_id: [3; 32], + encryption_scheme_id: [4; 32], + committee_public_key_hash: [5; 32], }; - - let encoded = encode_guest_input(&input).unwrap(); - let decoded: ComputeGuestInput = deserialize(&encoded).unwrap(); - let legacy: Vec = - bytemuck::pod_collect_to_vec(&risc0_zkvm::serde::to_vec(&encoded).unwrap()); - - assert_eq!(decoded.domain.e3_id, input.domain.e3_id); - assert_eq!( - decoded.input.fhe_inputs.ciphertexts, - input.input.fhe_inputs.ciphertexts - ); - assert_eq!(legacy.len(), encoded.len() * 4 + 4); - } - - #[test] - fn boundless_input_encoding_preserves_default() { - let input = [0, 127, 255]; - for program_url in [None, Some("https://example.org/program.bin")] { - for encoding in [None, Some("bincode")] { - assert_eq!( - encode_boundless_input(&input, encoding, program_url).unwrap(), - input - ); - } - } - } - - #[test] - fn boundless_input_encoding_matches_legacy_guest() { - let input = [0, 127, 255]; - let encoded = encode_boundless_input( - &input, - Some("risc0-serde"), - Some("https://example.org/program.bin"), - ) - .unwrap(); - assert_eq!( - encoded, - [3, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 255, 0, 0, 0] - ); - let decoded: Vec = risc0_zkvm::serde::from_slice(&encoded).unwrap(); - assert_eq!(decoded, input); - } - - #[test] - fn boundless_input_encoding_rejects_invalid_configuration() { - for program_url in [None, Some("")] { - assert!(encode_boundless_input(&[], Some("risc0-serde"), program_url).is_err()); - } - for encoding in ["", "unknown"] { - assert!( - encode_boundless_input(&[], Some(encoding), Some("https://example.org")).is_err() - ); - } - } - - #[test] - #[ignore = "requires an external guest and its raw bincode input"] - fn configured_guest_matches_host_journal() { - let guest = std::fs::read(std::env::var("RISC0_TEST_GUEST").unwrap()).unwrap(); - let input = std::fs::read(std::env::var("RISC0_TEST_INPUT").unwrap()).unwrap(); - let expected_image_id = std::env::var("RISC0_TEST_IMAGE_ID").unwrap(); - assert_eq!( - risc0_zkvm::compute_image_id(&guest).unwrap().to_string(), - expected_image_id - ); - let decoded: ComputeGuestInput = deserialize(&input).unwrap(); - let expected = ComputeJournal::new( - decoded.domain, - decoded.input.process(fhe_processor, policy()).unwrap(), - ) - .unwrap(); - let encoding = std::env::var("BOUNDLESS_INPUT_ENCODING").ok(); - let stdin = - encode_boundless_input(&input, encoding.as_deref(), Some("external-guest")).unwrap(); - let env = ExecutorEnv::builder().write_slice(&stdin).build().unwrap(); - let session = risc0_zkvm::default_executor().execute(env, &guest).unwrap(); - assert_eq!(session.journal.bytes, encode_journal(&expected).unwrap()); - println!( - "Guest execution matches all host journal fields; input root: {}", - hex::encode(expected.merkle_root) - ); - } - - #[test] - fn compute_result_journal_matches_crisp_layout() { - let domain = ComputeDomain::new( - 31_337, - "0x1111111111111111111111111111111111111111", - "7", - &[0x22; 32], - &[0x33; 32], - ) - .unwrap(); - let result = ComputeJournal::new( + let mut journal = ComputeJournal::new( domain, - e3_compute_provider::ComputeResult { - ciphertext_hash: (0_u8..32).collect(), - ciphertext_commitment: (32_u8..64).collect(), - params_hash: hex::decode( - "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - ) - .unwrap(), - merkle_root: hex::decode( - "2134e76ac5d21aab186c2be1dd8f84ee880a1e46eaf712f9d371b6df22191f3e", - ) - .unwrap(), + ComputeResult { + ciphertext_hash: vec![6; 32], + ciphertext_commitment: vec![7; 32], + params_hash: vec![8; 32], + merkle_root: vec![9; 32], }, ) .unwrap(); - - let journal = encode_journal(&result).expect("journal encoding failed"); - let expected = [ - result.chain_id.as_slice(), - result.verifying_contract.as_slice(), - result.e3_id.as_slice(), - result.encryption_scheme_id.as_slice(), - result.committee_public_key_hash.as_slice(), - result.ciphertext_hash.as_slice(), - result.ciphertext_commitment.as_slice(), - result.params_hash.as_slice(), - result.merkle_root.as_slice(), - ] - .into_iter() - .flat_map(risc0_vec32) - .collect::>(); - - assert_eq!(journal.len(), 1188); - assert_eq!(journal, expected); - assert_eq!( - hex::encode(Impl::hash_bytes(&journal).as_bytes()), - "4403934eb9404372d77f23454aeb4bb7f21bbe856c5c51fc3243f5e05cc2c702" - ); + let bytes = journal.abi_bytes().unwrap(); + assert_eq!(bytes.len(), 288); + assert_eq!(&bytes[..24], &[0; 24]); + assert_eq!(&bytes[32..44], &[0; 12]); + for (i, field) in bytes[64..].chunks_exact(32).enumerate() { + assert_eq!(field, &[i as u8 + 3; 32]); + } + let envelope = encode_compute_proof(&vec![0; 2144], &journal).unwrap(); + assert_eq!(envelope.len(), 2272); + assert_eq!(&envelope[32..64], &[8; 32]); + assert_eq!(&envelope[64..96], &[9; 32]); + assert!(encode_compute_proof(&[], &journal).is_err()); + journal.e3_id.pop(); + assert!(encode_compute_proof(&vec![0; 2144], &journal).is_err()); } #[test] - fn compute_proof_uses_solidity_parameter_encoding() { - let result = ComputeJournal { - chain_id: vec![0; 32], - verifying_contract: vec![0; 32], - e3_id: vec![0; 32], - encryption_scheme_id: vec![0; 32], - committee_public_key_hash: vec![0; 32], - ciphertext_hash: vec![0; 32], - ciphertext_commitment: vec![0; 32], - params_hash: vec![0x22; 32], - merkle_root: vec![0x33; 32], - }; - - let encoded = encode_compute_proof(&[0x11; 4], &result).unwrap(); - let (seal, params_hash, input_root) = - <(Bytes, B256, B256)>::abi_decode_params(&encoded).unwrap(); - - assert_eq!(seal.as_ref(), &[0x11; 4]); - assert_eq!(params_hash, B256::repeat_byte(0x22)); - assert_eq!(input_root, B256::repeat_byte(0x33)); + #[ignore = "Requires OPENVM_TEST_INPUT and OPENVM_TEST_JOURNAL"] + fn native_result_matches_external_guest_journal() -> Result<()> { + let input: ComputeGuestInput = + bincode::deserialize(&fs::read(env::var("OPENVM_TEST_INPUT")?)?)?; + let (result, _) = input + .input + .run(e3_user_program::fhe_processor, e3_user_program::policy()) + .map_err(|error| anyhow::anyhow!("{error}"))?; + let journal = ComputeJournal::new(input.domain, result).map_err(anyhow::Error::msg)?; + assert_eq!( + journal.abi_bytes().map_err(anyhow::Error::msg)?, + fs::read(env::var("OPENVM_TEST_JOURNAL")?)? + ); + Ok(()) } } diff --git a/crates/support/methods/Cargo.toml b/crates/support/methods/Cargo.toml deleted file mode 100644 index 41a537beae..0000000000 --- a/crates/support/methods/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "methods" -version = { workspace = true } -edition = { workspace = true } - -[package.metadata.risc0] -methods = ["guest"] - -[build-dependencies] -hex = { workspace = true } -risc0-build = { workspace = true } -risc0-build-ethereum = { workspace = true } -risc0-zkp = { workspace = true } - -[dev-dependencies] -alloy-primitives = { workspace = true } -alloy-sol-types = { workspace = true } -risc0-zkvm = { workspace = true } diff --git a/crates/support/methods/README.md b/crates/support/methods/README.md deleted file mode 100644 index 4b4bfa07ea..0000000000 --- a/crates/support/methods/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# zkVM Methods - -This directory contains the [zkVM] portion of your [RISC Zero] application. This is where you will -define one or more [guest programs] to act as a coprocessor to your [on-chain logic]. - -> In typical use cases, the only code in this directory that you will need to edit is inside -> [guest/src/bin]. - -### Writing Guest Code - -To learn to write code for the zkVM, we recommend [Guest Code 101]. - -Examples of what you can do in the guest can be found in the [RISC Zero examples]. - -### From Guest Code to Binary File - -Code in the `methods/guest` directory will be compiled into one or more binaries. - -Build configuration for the methods is included in `methods/build.rs`. - -Each will have a corresponding image ID, which is a hash identifying the program. - -[zkVM]: https://dev.risczero.com/zkvm -[RISC Zero]: https://www.risczero.com/ -[guest programs]: https://dev.risczero.com/terminology#guest-program -[on-chain logic]: ../contracts/ -[guest/src/bin]: ./guest/src/bin/ -[Guest Code 101]: https://dev.risczero.com/api/zkvm/guest-code-101 -[RISC Zero examples]: https://github.com/risc0/risc0/tree/main/examples diff --git a/crates/support/methods/build.rs b/crates/support/methods/build.rs deleted file mode 100644 index 3ae0be8baa..0000000000 --- a/crates/support/methods/build.rs +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -// Copyright 2023 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::{ - collections::HashMap, - env, fs, - path::{Path, PathBuf}, - process::Command, -}; - -use risc0_build::{ - embed_methods_with_options, DockerOptionsBuilder, GuestListEntry, GuestOptionsBuilder, -}; -use risc0_build_ethereum::generate_solidity_files; - -// Paths where the generated Solidity files will be written. -const SOLIDITY_IMAGE_ID_PATH: &str = "../contracts/ImageID.sol"; -const SOLIDITY_ELF_PATH: &str = "../tests/Elf.sol"; - -/// Reports whether the reproducible Docker guest build is selected. -/// -/// The variable is read for its value, not its presence, so `RISC0_USE_DOCKER=0` selects the -/// local build. -fn use_docker() -> bool { - matches!( - env::var("RISC0_USE_DOCKER").unwrap_or_default().as_str(), - "1" | "true" | "TRUE" | "yes" | "YES" - ) -} - -/// Builds and returns the pinned guest-builder image tag. -/// -/// risc0-build generates its own Dockerfile. Its default image has the wrong Rust version for the -/// pinned fhe.rs dependency and does not contain `protoc`. Build the small checked-in layer first, -/// then tell risc0-build to use it for the deterministic guest build. -fn guest_builder_tag(support_dir: &Path) -> String { - let dockerfile = support_dir.join("methods/guest-builder.Dockerfile"); - println!("cargo:rerun-if-changed={}", dockerfile.display()); - - let source = fs::read_to_string(&dockerfile).unwrap_or_else(|e| { - panic!( - "cannot read {} to resolve the guest toolchain: {e}", - dockerfile.display() - ) - }); - - let toolchain = source - .lines() - .find_map(|line| line.trim().strip_prefix("ARG RISC0_TOOLCHAIN=")) - .unwrap_or_else(|| panic!("no ARG RISC0_TOOLCHAIN in {}", dockerfile.display())) - .trim(); - - assert!( - !toolchain.is_empty(), - "ARG RISC0_TOOLCHAIN in {} is empty", - dockerfile.display() - ); - - let tag = format!("interfold-r0.{toolchain}-protoc-v1"); - let image = format!("risczero/risc0-guest-builder:{tag}"); - let status = Command::new("docker") - .args([ - "build", - "--platform", - "linux/amd64", - "--load", - "--provenance=false", - "--tag", - &image, - "--file", - ]) - .arg(&dockerfile) - .arg(support_dir) - .status() - .unwrap_or_else(|e| panic!("cannot start Docker to build {image}: {e}")); - assert!( - status.success(), - "failed to build the pinned RISC Zero guest-builder image {image}" - ); - - tag -} - -/// Copies each Docker-built ELF to the path used by the upload command. -fn copy_docker_elves_to_release(guests: &[GuestListEntry]) { - for guest in guests { - let source = Path::new(guest.path.as_ref()); - let docker_dir = source.parent().unwrap_or_else(|| { - panic!( - "Docker guest ELF has no parent directory: {}", - source.display() - ) - }); - if docker_dir.file_name().and_then(|name| name.to_str()) != Some("docker") { - panic!( - "Docker guest ELF is outside the Docker profile: {}", - source.display() - ); - } - - let profile_root = docker_dir.parent().unwrap_or_else(|| { - panic!( - "Docker guest profile has no parent: {}", - docker_dir.display() - ) - }); - let release_dir = profile_root.join("release"); - fs::create_dir_all(&release_dir).unwrap_or_else(|e| { - panic!( - "cannot create upload artifact directory {}: {e}", - release_dir.display() - ) - }); - - let file_name = source - .file_name() - .unwrap_or_else(|| panic!("Docker guest ELF has no file name: {}", source.display())); - let destination = release_dir.join(file_name); - fs::copy(source, &destination).unwrap_or_else(|e| { - panic!( - "cannot copy Docker guest ELF from {} to {}: {e}", - source.display(), - destination.display() - ) - }); - } -} - -fn main() { - // Builds can be made deterministic, and thereby reproducible, by using Docker to build the - // guest. Set RISC0_USE_DOCKER to 1 (or true) to select the reproducible Docker build. Any - // other value, and an unset variable, select the local build. - println!("cargo:rerun-if-env-changed=RISC0_USE_DOCKER"); - println!("cargo:rerun-if-changed=build.rs"); - let manifest_dir = PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()); - let reproducible = use_docker(); - let mut builder = GuestOptionsBuilder::default(); - if reproducible { - let support_dir = manifest_dir.join("../"); - // The official guest-builder image is linux/amd64. Set the platform for the nested Docker - // build as well, so Apple Silicon developers produce the same ELF as CI. - env::set_var("DOCKER_DEFAULT_PLATFORM", "linux/amd64"); - let docker_options = DockerOptionsBuilder::default() - .root_dir(support_dir.clone()) - .docker_container_tag(guest_builder_tag(&support_dir)) - .build() - .unwrap(); - builder.use_docker(docker_options); - } - let guest_options = builder.build().unwrap(); - - // Generate Rust source files for the methods crate. - let guests = embed_methods_with_options(HashMap::from([("guests", guest_options)])); - - if reproducible { - copy_docker_elves_to_release(&guests); - } - - // A native guest build is useful for local development, but its image ID can vary with the - // host toolchain. Never let such a build replace the production trust anchor checked into the - // repository. Only the pinned Docker build may update ImageID.sol and Elf.sol. - if reproducible && std::env::var("SKIP_SOLIDITY").unwrap_or_default() != "1" { - // Generate Solidity source files for use with Forge. - let solidity_opts = risc0_build_ethereum::Options::default() - .with_image_id_sol_path(SOLIDITY_IMAGE_ID_PATH) - .with_elf_sol_path(SOLIDITY_ELF_PATH); - generate_solidity_files(guests.as_slice(), &solidity_opts).unwrap(); - } else if !reproducible { - println!( - "cargo:warning=Skipping Solidity codegen for a non-reproducible native guest build" - ); - } else { - println!("cargo:warning=Skipping Solidity codegen (SKIP_SOLIDITY set)"); - } -} diff --git a/crates/support/methods/guest-builder.Dockerfile b/crates/support/methods/guest-builder.Dockerfile deleted file mode 100644 index 4cd48df094..0000000000 --- a/crates/support/methods/guest-builder.Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -ARG RISC0_TOOLCHAIN=1.91.1 - -# Keep the base image content-addressed. The tag documents the matching RISC Zero Rust -# toolchain; the digest prevents a registry-side tag change from changing the guest ELF. -FROM risczero/risc0-guest-builder:r0.${RISC0_TOOLCHAIN}@sha256:fafb377a44e1cfca415577c48d2f7012bda99ed36f2fae27f9a663b9fe6048f0 - -# fhe.rs generates its Protobuf bindings while the guest dependency graph is compiled. -# The upstream RISC Zero guest-builder image does not include protoc. -RUN apt-get update && \ - apt-get install -y --no-install-recommends protobuf-compiler=3.12.4-1ubuntu7.22.04.6 && \ - rm -rf /var/lib/apt/lists/* diff --git a/crates/support/methods/guest/Cargo.toml b/crates/support/methods/guest/Cargo.toml deleted file mode 100644 index e89018045f..0000000000 --- a/crates/support/methods/guest/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "guests" -version = "0.1.0" -edition = "2021" -resolver = "3" -rust-version = "1.85.0" - -[workspace] - -[[bin]] -name = "program" -path = "src/bin/program.rs" - -[dependencies] -# `heap-embedded-alloc` replaces the default bump allocator, which never reclaims memory. -# -# The Secure Process holds only one ciphertext's working set at a time: `compute_leaf_hashes` -# converts each input to its Greco form, takes the commitment, and drops it before the next. Under -# the bump allocator every one of those temporaries is retained anyway, so peak memory grows with -# the round rather than staying flat. -# -# At the secure preset one Greco form is 49152 coefficients (degree 8192 x 3 CRT limbs x 2 -# polynomials) held as `num_bigint::BigInt`, which costs about 48 bytes per coefficient against -# 8 bytes as a raw word — roughly 2.4 MB per ciphertext, or 7x the 356 KB serialized form. At 500 -# inputs that is ~1.2 GB of retained temporaries alone, and the guest aborts with -# "Out of memory! You have been using the default bump allocator" partway through a round. -# -# Measured: N=100 completes, N=500 aborts after ~43 minutes of Boundless preflight. The feature -# costs extra cycles per allocation, which is the price of a round size that scales. -risc0-zkvm = { version = "=3.0.3", default-features = false, features = [ - 'std', - 'heap-embedded-alloc', -] } -# This revision decides which compute-provider code runs inside the zkVM, so it decides the image -# ID. It must match the pin in crates/support/Cargo.toml. See that file for why the dependency is -# pinned by revision instead of by path. -e3-compute-provider = { git = "https://github.com/theinterfold/interfold", rev = "5668f4c9ee0992aeb05b320eaa3b998a6c32e525" } -e3-support-types = { path = "../../types" } -e3-user-program = { path = "../../program" } -bincode = "=1.3.3" - -[profile.release] -lto = "thin" diff --git a/crates/support/methods/guest/README.md b/crates/support/methods/guest/README.md deleted file mode 100644 index 8b15192678..0000000000 --- a/crates/support/methods/guest/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Guest Programs - -Each file in the [`src/bin`](./src/bin) folder defines a program for the zkVM. We refer to the -program running in the zkVM as the "[guest]". - -To learn more about writing guest programs, check out the zkVM [developer docs]. For zkVM API -documentation, see the [guest module] of the [`risc0-zkvm`] crate. - -[guest]: https://dev.risczero.com/terminology#guest -[developer docs]: https://dev.risczero.com/zkvm -[guest module]: https://docs.rs/risc0-zkvm/latest/risc0_zkvm/guest/index.html -[`risc0-zkvm`]: https://docs.rs/risc0-zkvm/latest/risc0_zkvm/index.html diff --git a/crates/support/methods/guest/src/bin/program.rs b/crates/support/methods/guest/src/bin/program.rs deleted file mode 100644 index be56db1ac3..0000000000 --- a/crates/support/methods/guest/src/bin/program.rs +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use bincode::deserialize; -use e3_support_types::{ComputeGuestInput, ComputeJournal}; -use e3_user_program::{fhe_processor, policy}; -use risc0_zkvm::guest::env; -use std::io::Read; - -fn main() { - let mut input_slice = Vec::::new(); - env::stdin().read_to_end(&mut input_slice).unwrap(); - // The host sends raw bincode bytes. RISC Zero serde is reserved for the committed journal. - let input: ComputeGuestInput = deserialize(&input_slice).unwrap(); - - // The policy comes from the user program, not from a default here: it decides the input-tree - // leaf and which inputs count, and both have to agree with what the E3 program's contract did. - let result = input.input.process(fhe_processor, policy()).unwrap(); - let journal = ComputeJournal::new(input.domain, result).unwrap(); - - env::commit(&journal); -} diff --git a/crates/support/methods/src/lib.rs b/crates/support/methods/src/lib.rs deleted file mode 100644 index 0d7f0a83f4..0000000000 --- a/crates/support/methods/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -// Copyright 2023 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Generated crate containing the image ID and ELF binary of the build guest. -include!(concat!(env!("OUT_DIR"), "/methods.rs")); diff --git a/crates/support/openvm/README.md b/crates/support/openvm/README.md new file mode 100644 index 0000000000..3b74a41d8e --- /dev/null +++ b/crates/support/openvm/README.md @@ -0,0 +1,166 @@ +# CRISP OpenVM compute backend + +OpenVM replaces RISC Zero and Boundless in the support service and the CRISP deployment path. This +is a new guest and verifier deployment, not an upgrade of an existing receipt. Existing deployment +records and legacy RISC Zero contracts remain unchanged. This branch does not deploy contracts or +change a live network. + +## Build + +Use Rust 1.91.1 and the OpenVM CLI and guest toolchain for the pinned v2.0.2 SDK. Install the SDK +prerequisites before these commands. CUDA builds also require the CUDA toolkit, driver libraries, +and the correct GPU architecture in the build environment. + +From the repository root: + +```sh +pnpm openvm setup-fhe +pnpm openvm guest build +pnpm openvm guest keygen --app-only +pnpm openvm prover-build --features cuda +pnpm openvm service-build --release +``` + +Omit `--features cuda` for a CPU worker. The native HTTP service has no SDK or CUDA dependency. The +worker is a separate executable so a proof failure does not abort the service process. + +The FHE setup checks out a fixed revision and applies the checked-in optimization patch under +`target/openvm/fhe`. It refuses unrelated changes. The optimized guest enables direct coefficient +packing, canonical power-basis decoding, lazy BFV products, modular Poseidon2, SHA-256, and Keccak. +The native service uses the same CRISP policy source and compares its journal with the proved +output. + +Use the built worker's `prepare ` command to generate +the full aggregation key and application identity. Do not use an aggregation key from another VM +configuration. `check` and `prove` derive the identity from the executable and keys and reject a +mismatch. + +Obtain the compatible Halo2 proving key, KZG parameters, and generated verifier artifact for the +pinned OpenVM release. Verify their provenance and checksums. Keep all generated artifacts under +`target/` or outside the repository. Never commit proving keys, proofs, inputs, benchmark reports, +operator accounts, or machine-specific configuration. + +## Worker configuration + +Create a private deployment-local JSON configuration with these fields. There are no deployment +identity or path defaults. + +| Field | Value | +| ---------------------- | ------------------------------------------------------------------------ | +| `app_pk` | Absolute path to the guest application proving key | +| `executable` | Absolute path to the guest VM executable | +| `aggregation_pk` | Absolute path to the full aggregation key from `prepare` | +| `halo2_pk` | Absolute path to the compatible Halo2 proving key | +| `halo2_params_dir` | Absolute path to the KZG parameter directory | +| `verifier_artifact` | Absolute path to the SDK-generated verifier bytecode JSON | +| `verifier_sha256` | SHA-256 digest of that JSON file, lowercase hexadecimal without a prefix | +| `app_commit` | The `app_commit` object from `prepare`'s identity JSON | +| `segment_memory_bytes` | Nonzero segment memory limit for the prover machine | + +Run `interfold-openvm-prover check ` before service startup. Configure +`OPENVM_PROVER_BIN` and `OPENVM_PROVER_CONFIG` with absolute file paths, then run +`pnpm openvm service-start`. For the Interfold CLI, set `program.openvm.repository`, +`program.openvm.prover_bin`, and `program.openvm.prover_config`; these are deployment-local paths. +Legacy `program.risc0` settings do not select a fallback backend. Explicit `program.dev` remains a +separate development runner and does not produce an OpenVM receipt. + +The service binds to `127.0.0.1:13151` by default. Set `OPENVM_BIND_ADDR` to change the listener. +The container binds to `0.0.0.0:13151`; restrict its published port and network access. The JSON +request limit is 128 MiB. Set `OPENVM_MAX_REQUEST_BYTES` to change it, up to 1 GiB. The guest's +binary input limit is separate and remains 512 MiB minus 16 bytes. + +The existing `POST /run_compute` and completed/failed callback formats remain unchanged. The worker +generates an application proof, recursive aggregate, and Halo2 EVM proof. It executes the configured +EVM verifier, checks both application commitments, and checks the expected journal before it writes +a seal. A failed proof sends a failed callback. There is no fake-proof mode. + +Jobs are in memory, with one active computation per service process by default. Set +`MAX_CONCURRENT_COMPUTATIONS` only when the machine can prove that many jobs concurrently. A restart +can lose an accepted job. Operators must reconcile jobs and retry failed callback delivery; this +change does not add a durable job queue. Run the service behind authenticated admission control. Set +callback access policy for the deployment; do not expose an unrestricted service to the Internet. + +## Contract migration + +The guest reveals SHA-256 of nine consecutive 32-byte ABI words: + +1. Chain ID +2. Interfold address +3. Full uint256 E3 ID +4. Encryption scheme ID +5. Committee public-key hash +6. Ciphertext output hash +7. SAFE ciphertext commitment +8. Parameter hash +9. Input root + +The seal is `abi.encode(uint8(1), bytes(halo2ProofData), bytes32[9](journalWords))`. The compute +envelope remains `abi.encode(bytes(seal), bytes32(paramsHash), bytes32(inputRoot))`. The journal is +288 bytes, not the legacy RISC Zero serialization. + +The CRISP deploy script requires `OPENVM_APP_EXE_COMMIT` and `OPENVM_APP_VM_COMMIT`, plus exactly +one Halo2 verifier source: + +- `OPENVM_VERIFIER_ARTIFACT` and `OPENVM_VERIFIER_SHA256`: check and deploy the bytecode JSON. +- `OPENVM_HALO2_VERIFIER` and `OPENVM_HALO2_RUNTIME_CODE_HASH`: check an existing deployment's code. + +It installs `OpenVmReceiptVerifier` and `OpenVmBfvCiphertextVerifier`. Missing configuration stops +deployment. Its mock mode applies only to other test components; it never creates a mock compute +receipt verifier. The template permits an explicitly unproved test only with +`TEMPLATE_UNPROVED_TEST=1` on chain ID 31337. + +The receipt identity binds the Halo2 verifier address, executable commitment, and VM commitment. +Both the protocol BFV verifier and CRISP application verifier must use that identity. Both +verification calls remain mandatory. CRISP independently checks its stored parameter hash and input +root. Existing rounds retain their request-time verifier snapshot and must drain before a live +migration. The historical RISC Zero mainnet activation scripts are not OpenVM migration scripts. Do +not use them to activate this backend. + +No gas override or proof-verification bypass is included. On-chain verifier optimization is separate +work. The compute path remains unaudited. + +## Checks + +```sh +pnpm openvm service-test +pnpm openvm contract-test +``` + +`pnpm openvm proof-test` requires externally supplied `OPENVM_TEST_IDENTITY`, `OPENVM_TEST_JOURNAL`, +`OPENVM_TEST_VERIFIER`, and `OPENVM_TEST_VERIFIER_SHA256`. Set `OPENVM_TEST_PROOF` to a proof JSON +file or `OPENVM_TEST_SEAL` to a binary seal from the worker. It verifies a real proof on an +in-memory chain and rejects changed journal words, application commitments, and proof data. It does +not submit a public transaction. No local proof fixture is part of this branch. + +### Live HTTP round + +`pnpm openvm service-e2e` exercises CRISP input submission and indexing, the running OpenVM service, +the HTTP callback, and automatic ciphertext publication. It requires an isolated loopback RPC with +chain ID 31337 and a running, configured program service. Use Anvil for long local rounds: the +pinned Hardhat node can expire live subscriptions after five minutes. + +Build the CRISP server with `pnpm openvm crisp-server-build --release`. Generate fresh test inputs +with `pnpm openvm fixture 100 `. The fixture uses the secure-8192 preset. The +generator keeps its secret key in memory and checks the native aggregate and plaintext before +writing the fixture. + +Set these test-only environment variables: + +| Variable | Meaning | +| ----------------------------- | ---------------------------------------------------------- | +| `LOCAL_RPC_URL` | Isolated loopback EVM RPC | +| `OPENVM_E2E_FIXTURE` | Directory generated by the fixture command | +| `OPENVM_E2E_SERVER` | Absolute path to the CRISP server binary | +| `OPENVM_E2E_OUTPUT` | New directory for the test report and logs | +| `OPENVM_E2E_PROGRAM_URL` | Running program service reachable from CRISP | +| `OPENVM_E2E_CALLBACK_URL` | CRISP URL reachable from the program service | +| `OPENVM_E2E_LOCAL_SERVER_URL` | Local CRISP listener; defaults to `http://127.0.0.1:14000` | +| `OPENVM_TEST_IDENTITY` | Prepared identity JSON matching the worker | +| `OPENVM_TEST_VERIFIER` | Halo2 verifier bytecode JSON matching the worker | +| `OPENVM_TEST_VERIFIER_SHA256` | Expected SHA-256 of that JSON | + +The test deploys real OpenVM receipt and protocol verifiers. It rejects a changed proof, checks the +indexed tally, and checks settlement. Randomness, DKG proofs, ballot proofs and census, data +availability, and threshold-decryption proofs are explicit local mocks. This is a real compute-proof +integration test, not proof of a fully cryptographic distributed E3 round. Reports, inputs, and +generated proofs stay in the supplied output directories and must not be committed. diff --git a/crates/support/openvm/fhe-optimizations.patch b/crates/support/openvm/fhe-optimizations.patch new file mode 100644 index 0000000000..dd63d504c7 --- /dev/null +++ b/crates/support/openvm/fhe-optimizations.patch @@ -0,0 +1,403 @@ +diff --git a/crates/fhe-math/Cargo.toml b/crates/fhe-math/Cargo.toml +index 54d9cf8..671d5be 100644 +--- a/crates/fhe-math/Cargo.toml ++++ b/crates/fhe-math/Cargo.toml +@@ -1,4 +1,5 @@ + [package] ++workspace = "../.." + name = "fhe-math" + description = "Mathematical utilities for the fhe.rs library" + authors.workspace = true +diff --git a/crates/fhe-math/src/rq/convert.rs b/crates/fhe-math/src/rq/convert.rs +index bf94490..af20a2a 100644 +--- a/crates/fhe-math/src/rq/convert.rs ++++ b/crates/fhe-math/src/rq/convert.rs +@@ -11,6 +11,7 @@ use crate::{ + use itertools::{Itertools, izip}; + use ndarray::{Array2, ArrayView, Axis}; + use num_bigint::BigUint; ++use prost::Message; + use std::sync::Arc; + use zeroize::{Zeroize, Zeroizing}; + +@@ -106,6 +107,33 @@ impl TryConvertFrom<&Rq> for Poly { + } + } + ++impl Poly { ++ /// Reads canonical power-basis coefficients from an NTT-tagged serialization. ++ /// Returns `None` when the caller must use the standard decoder. ++ pub fn power_basis_from_bytes_if_canonical( ++ bytes: &[u8], ++ ctx: &Arc, ++ ) -> Result>> { ++ let value: Rq = Message::decode(bytes).map_err(|e| Error::Serialization(e.to_string()))?; ++ if value.degree as usize != ctx.degree { ++ return Ok(None); ++ } ++ let (representation, coefficients, variable_time) = parse_proto(&value, ctx, false)?; ++ if representation != Representation::Ntt ++ || coefficients.len() != ctx.moduli.len() * ctx.degree ++ { ++ return Ok(None); ++ } ++ // The standard NTT round trip can reduce noncanonical coefficients. Keep that path. ++ for (row, modulus) in coefficients.chunks_exact(ctx.degree).zip(ctx.moduli.iter()) { ++ if row.iter().any(|coefficient| coefficient >= modulus) { ++ return Ok(None); ++ } ++ } ++ Poly::::try_convert_from(coefficients, ctx, variable_time).map(Some) ++ } ++} ++ + impl TryConvertFrom<&Rq> for Poly { + fn try_convert_from(value: &Rq, ctx: &Arc, variable_time: bool) -> Result { + let (representation_from_proto, coefficients, variable_time) = +diff --git a/crates/fhe-math/src/rq/serialize.rs b/crates/fhe-math/src/rq/serialize.rs +index 45f1460..9f13560 100644 +--- a/crates/fhe-math/src/rq/serialize.rs ++++ b/crates/fhe-math/src/rq/serialize.rs +@@ -43,6 +43,58 @@ mod tests { + 4611686018309947393, + ]; + ++ #[test] ++ fn direct_power_basis_decode_matches_the_ntt_round_trip() -> Result<(), Box> { ++ for degree in [16, 512, 8192] { ++ let ctx = Context::new_arc(Q, degree)?; ++ let values: Vec = Q ++ .iter() ++ .flat_map(|q| { ++ (0..degree).map(move |i| match i % 4 { ++ 0 => 0, ++ 1 => 1, ++ 2 => q / 2, ++ _ => q - 1, ++ }) ++ }) ++ .collect(); ++ let power = Poly::::try_convert_from(values, &ctx, false)?; ++ let ntt = power.clone().into_ntt(); ++ let bytes = ntt.to_bytes(); ++ let direct = Poly::::power_basis_from_bytes_if_canonical(&bytes, &ctx)?.unwrap(); ++ let standard = Poly::::from_bytes(&bytes, &ctx)?.to_power_basis(); ++ assert_eq!(direct, standard); ++ assert_eq!(direct, power); ++ } ++ Ok(()) ++ } ++ ++ #[test] ++ fn direct_power_basis_decode_requires_canonical_coefficients() -> Result<(), Box> { ++ let ctx = Context::new_arc(&Q[..1], 16)?; ++ let poly = Poly::::zero(&ctx); ++ let mut proto = Rq::decode(poly.to_bytes().as_slice())?; ++ proto.coefficients = crate::zq::Modulus::new(Q[0])?.serialize_vec(&vec![Q[0]; 16]); ++ assert!( ++ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? ++ .is_none() ++ ); ++ proto = Rq::decode(poly.to_bytes().as_slice())?; ++ proto.degree = 8; ++ assert!( ++ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? ++ .is_none() ++ ); ++ proto = Rq::decode(poly.to_bytes().as_slice())?; ++ proto.representation = RepresentationProto::Powerbasis as i32; ++ assert!( ++ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? ++ .is_none() ++ ); ++ assert!(Poly::::power_basis_from_bytes_if_canonical(&[255], &ctx).is_err()); ++ Ok(()) ++ } ++ + #[test] + fn serialize() -> Result<(), Box> { + let mut rng = rng(); +diff --git a/crates/fhe-traits/Cargo.toml b/crates/fhe-traits/Cargo.toml +index dba63aa..a1cec02 100644 +--- a/crates/fhe-traits/Cargo.toml ++++ b/crates/fhe-traits/Cargo.toml +@@ -1,4 +1,5 @@ + [package] ++workspace = "../.." + name = "fhe-traits" + description = "Traits for the fhe.rs library" + authors.workspace = true +diff --git a/crates/fhe-util/Cargo.toml b/crates/fhe-util/Cargo.toml +index 72a16dc..a8b1949 100644 +--- a/crates/fhe-util/Cargo.toml ++++ b/crates/fhe-util/Cargo.toml +@@ -1,4 +1,5 @@ + [package] ++workspace = "../.." + name = "fhe-util" + description = "Utilities for the fhe.rs library" + authors.workspace = true +diff --git a/crates/fhe/Cargo.toml b/crates/fhe/Cargo.toml +index a11bd83..b0400d1 100644 +--- a/crates/fhe/Cargo.toml ++++ b/crates/fhe/Cargo.toml +@@ -1,4 +1,5 @@ + [package] ++workspace = "../.." + name = "fhe" + description = "Fully Homomorphic Encryption in Rust" + authors.workspace = true +diff --git a/crates/fhe/src/bfv/ciphertext.rs b/crates/fhe/src/bfv/ciphertext.rs +index 01d4211..c0fbd57 100644 +--- a/crates/fhe/src/bfv/ciphertext.rs ++++ b/crates/fhe/src/bfv/ciphertext.rs +@@ -3,7 +3,7 @@ + use crate::bfv::{parameters::BfvParameters, traits::TryConvertFrom}; + use crate::proto::bfv::Ciphertext as CiphertextProto; + use crate::{Error, Result, SerializationError}; +-use fhe_math::rq::{Ntt, Poly}; ++use fhe_math::rq::{Ntt, Poly, PowerBasis}; + use fhe_traits::{ + DeserializeParametrized, DeserializeWithContext, FheCiphertext, FheParametrized, Serialize, + }; +@@ -44,6 +44,33 @@ impl DerefMut for Ciphertext { + } + + impl Ciphertext { ++ /// Reads two canonical level-zero components without an NTT round trip. ++ /// Returns `None` for encodings that require the standard decoder. ++ pub fn power_basis_from_bytes_if_canonical( ++ bytes: &[u8], ++ par: &Arc, ++ ) -> Result>>> { ++ let value: CiphertextProto = Message::decode(bytes).map_err(|_| { ++ Error::SerializationError(SerializationError::ProtobufError { ++ message: "Ciphertext decode".into(), ++ }) ++ })?; ++ if value.level != 0 || !value.seed.is_empty() || value.c.len() != 2 { ++ return Ok(None); ++ } ++ let context = par.context_at_level(0)?; ++ let mut components = Vec::with_capacity(2); ++ for bytes in value.c { ++ let Some(component) = ++ Poly::::power_basis_from_bytes_if_canonical(&bytes, context)? ++ else { ++ return Ok(None); ++ }; ++ components.push(component); ++ } ++ Ok(Some(components)) ++ } ++ + /// Create a ciphertext from a vector of polynomials. + /// A ciphertext must contain at least two polynomials, and all polynomials + /// must be in Ntt representation and with the same context. +diff --git a/crates/fhe/src/bfv/context/chain.rs b/crates/fhe/src/bfv/context/chain.rs +index a07a642..b1a701f 100644 +--- a/crates/fhe/src/bfv/context/chain.rs ++++ b/crates/fhe/src/bfv/context/chain.rs +@@ -5,7 +5,10 @@ use fhe_math::{ + rq::{Context, scaler::Scaler}, + }; + +-use crate::bfv::{context::CipherPlainContext, parameters::MultiplicationParameters}; ++use crate::bfv::{ ++ context::CipherPlainContext, ++ parameters::{MultiplicationParameters, MultiplicationParametersSource}, ++}; + + /// A context in the modulus switching chain + #[derive(Debug, Clone)] +@@ -29,6 +32,7 @@ pub struct ContextLevel { + /// Parameters required for ciphertext-ciphertext multiplication at this + /// level + pub(crate) mul_params: OnceLock, ++ pub(crate) mul_params_source: OnceLock>, + } + + impl PartialEq for ContextLevel { +@@ -43,6 +47,7 @@ impl PartialEq for ContextLevel { + down_scaler: _, + up_scaler: _, + mul_params: _, ++ mul_params_source: _, + } = self; + let Self { + poly_context: other_poly_context, +@@ -54,6 +59,7 @@ impl PartialEq for ContextLevel { + down_scaler: _, + up_scaler: _, + mul_params: _, ++ mul_params_source: _, + } = other; + + // OnceCell fields are lazily computed caching fields, not part of equality. +@@ -84,6 +90,7 @@ impl ContextLevel { + down_scaler: OnceLock::new(), + up_scaler: OnceLock::new(), + mul_params: OnceLock::new(), ++ mul_params_source: OnceLock::new(), + } + } + +@@ -134,9 +141,13 @@ impl ContextLevel { + /// Access multiplication parameters for this level + #[expect(clippy::expect_used, reason = "bounds are validated before use")] + pub(crate) fn mul_params(&self) -> &MultiplicationParameters { +- self.mul_params +- .get() +- .expect("multiplication parameters not set") ++ self.mul_params.get_or_init(|| { ++ self.mul_params_source ++ .get() ++ .expect("multiplication parameter source not set") ++ .build(self) ++ .expect("cannot construct multiplication parameters") ++ }) + } + } + +diff --git a/crates/fhe/src/bfv/parameters.rs b/crates/fhe/src/bfv/parameters.rs +index 9b2e770..edad6bc 100644 +--- a/crates/fhe/src/bfv/parameters.rs ++++ b/crates/fhe/src/bfv/parameters.rs +@@ -16,7 +16,7 @@ use num_traits::{PrimInt as _, ToPrimitive}; + use prost::Message; + use std::collections::HashMap; + use std::fmt::Debug; +-use std::sync::Arc; ++use std::sync::{Arc, OnceLock}; + + /// Enum to support both small (u64) and large (BigUint) plaintext moduli. + #[derive(Debug, PartialEq, Eq, Clone)] +@@ -689,33 +689,17 @@ impl BfvParametersBuilder { + } + let context_chain = nodes.first().unwrap().clone(); + +- // Create n+1 moduli of 62 bits for multiplication. +- let mut extended_basis = Vec::with_capacity(moduli.len() + 1); +- let mut upper_bound = 1 << 62; +- while extended_basis.len() != moduli.len() + 1 { +- upper_bound = generate_prime(62, 2 * self.degree as u64, upper_bound).unwrap(); +- if !extended_basis.contains(&upper_bound) && !moduli.contains(&upper_bound) { +- extended_basis.push(upper_bound) +- } +- } +- +- // Compute multiplication parameters for each level +- for (i, node) in nodes.iter().enumerate() { +- // For the first multiplication, we want to extend to a context that +- // is ~60 bits larger. +- let modulus_size = moduli_sizes[..moduli_sizes.len() - i].iter().sum::(); +- let n_moduli = (modulus_size + 60).div_ceil(62); +- let mut mul_1_moduli = vec![]; +- mul_1_moduli.append(&mut moduli[..moduli_sizes.len() - i].to_vec()); +- mul_1_moduli.append(&mut extended_basis[..n_moduli].to_vec()); +- let mul_1_ctx = Context::new_arc(&mul_1_moduli, self.degree)?; +- let mp = MultiplicationParameters::new( +- &node.poly_context, +- &mul_1_ctx, +- ScalingFactor::one(), +- ScalingFactor::new(plaintext_big, node.poly_context.modulus()), +- )?; +- node.mul_params.set(mp).unwrap(); ++ // Addition does not need the extended multiplication basis or its NTT tables. ++ let mul_params_source = Arc::new(MultiplicationParametersSource { ++ moduli: moduli.clone(), ++ plaintext: plaintext_big.clone(), ++ degree: self.degree, ++ extended_basis: OnceLock::new(), ++ }); ++ for node in &nodes { ++ node.mul_params_source ++ .set(mul_params_source.clone()) ++ .unwrap(); + } + + // We use the same code as SEAL +@@ -799,6 +783,46 @@ impl Deserialize for BfvParameters { + type Error = Error; + } + ++/// Immutable inputs used to construct multiplication tables on first use. ++#[derive(Debug)] ++pub(crate) struct MultiplicationParametersSource { ++ moduli: Vec, ++ plaintext: BigUint, ++ degree: usize, ++ extended_basis: OnceLock>, ++} ++ ++impl MultiplicationParametersSource { ++ pub(crate) fn build(&self, node: &ContextLevel) -> Result { ++ let extended_basis = self.extended_basis.get_or_init(|| { ++ let mut basis = Vec::with_capacity(self.moduli.len() + 1); ++ let mut upper_bound = 1 << 62; ++ while basis.len() != self.moduli.len() + 1 { ++ upper_bound = generate_prime(62, 2 * self.degree as u64, upper_bound).unwrap(); ++ if !basis.contains(&upper_bound) && !self.moduli.contains(&upper_bound) { ++ basis.push(upper_bound); ++ } ++ } ++ basis ++ }); ++ let level_moduli = node.poly_context.moduli(); ++ let modulus_size = level_moduli ++ .iter() ++ .map(|m| 64 - m.leading_zeros() as usize) ++ .sum::(); ++ let n_moduli = (modulus_size + 60).div_ceil(62); ++ let mut mul_moduli = level_moduli.to_vec(); ++ mul_moduli.extend_from_slice(&extended_basis[..n_moduli]); ++ let mul_context = Context::new_arc(&mul_moduli, self.degree)?; ++ MultiplicationParameters::new( ++ &node.poly_context, ++ &mul_context, ++ ScalingFactor::one(), ++ ScalingFactor::new(&self.plaintext, node.poly_context.modulus()), ++ ) ++ } ++} ++ + /// Multiplication parameters + #[derive(Debug, Clone, PartialEq, Eq, Default)] + pub(crate) struct MultiplicationParameters { +@@ -833,6 +857,36 @@ mod tests { + use prost::Message; + use std::error::Error; + ++ #[test] ++ fn multiplication_tables_are_lazy_and_do_not_change_serialization() { ++ let params = BfvParametersBuilder::new() ++ .set_degree(16) ++ .set_plaintext_modulus(1153) ++ .set_moduli_sizes(&[50, 50]) ++ .build() ++ .unwrap(); ++ let bytes = params.to_bytes(); ++ let head = params.context_chain(); ++ for node in head.iter_chain() { ++ assert!(node.mul_params.get().is_none()); ++ assert!( ++ node.mul_params_source ++ .get() ++ .unwrap() ++ .extended_basis ++ .get() ++ .is_none() ++ ); ++ } ++ let first = head.mul_params() as *const _; ++ assert_eq!(first, head.mul_params() as *const _); ++ assert!(head.next.get().unwrap().mul_params.get().is_none()); ++ assert_eq!(params.to_bytes(), bytes); ++ assert_eq!(params, BfvParameters::try_deserialize(&bytes).unwrap()); ++ let source = head.mul_params_source.get().unwrap(); ++ assert_eq!(head.mul_params(), &source.build(&head).unwrap()); ++ } ++ + #[test] + fn default() { + let params = BfvParameters::default_arc(1, 16); diff --git a/crates/support/methods/guest/Cargo.lock b/crates/support/openvm/guest/Cargo.lock similarity index 72% rename from crates/support/methods/guest/Cargo.lock rename to crates/support/openvm/guest/Cargo.lock index 3572d46c52..4abbaf18b8 100644 --- a/crates/support/methods/guest/Cargo.lock +++ b/crates/support/openvm/guest/Cargo.lock @@ -16,9 +16,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -51,7 +51,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -79,7 +79,7 @@ dependencies = [ "derive_more", "foldhash 0.2.0", "hashbrown 0.16.1", - "indexmap", + "indexmap 2.14.2", "itoa", "k256", "keccak-asm", @@ -89,15 +89,15 @@ dependencies = [ "ruint", "rustc-hash", "serde", - "sha3", + "sha3 0.10.8", "tiny-keccak", ] [[package]] name = "alloy-rlp" -version = "0.3.12" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" dependencies = [ "arrayvec", "bytes", @@ -105,13 +105,13 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" +checksum = "60dd79f578c3912f1fc2a150dbeb8110b8cfb976c60f98ebf6de9d5da5965a2b" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error2", + "proc-macro-error3", "proc-macro2", "quote", "syn 2.0.119", @@ -119,27 +119,27 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" +checksum = "9edb8520f2f94275e1caa73c85207dcc78ec402a9a4c429240f9a0783a8f16c0" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap", - "proc-macro-error2", + "indexmap 2.14.2", + "proc-macro-error3", "proc-macro2", "quote", + "sha3 0.11.0", "syn 2.0.119", "syn-solidity", - "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" +checksum = "66af2d9344882172993be5f5cbfd349fdfa52cb548f7af8715b446fb35ef6001" dependencies = [ "const-hex", "dunce", @@ -158,7 +158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -173,6 +173,15 @@ dependencies = [ "serde", ] +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -248,41 +257,7 @@ checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" dependencies = [ "ark-ec 0.5.0", "ark-ff 0.5.0", - "ark-r1cs-std", - "ark-std 0.5.0", -] - -[[package]] -name = "ark-crypto-primitives" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" -dependencies = [ - "ahash", - "ark-crypto-primitives-macros", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-snark", "ark-std 0.5.0", - "blake2", - "derivative", - "digest 0.10.7", - "fnv", - "merlin", - "sha2", -] - -[[package]] -name = "ark-crypto-primitives-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", ] [[package]] @@ -381,6 +356,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af" +dependencies = [ + "ark-ff-asm 0.6.0", + "ark-ff-macros 0.6.0", + "ark-serialize 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "educe", + "num-bigint", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -411,6 +403,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "ark-ff-asm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -450,18 +452,16 @@ dependencies = [ ] [[package]] -name = "ark-groth16" -version = "0.5.0" +name = "ark-ff-macros" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e" +checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" dependencies = [ - "ark-crypto-primitives", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-poly 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-std 0.5.0", + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -492,35 +492,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "ark-r1cs-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" -dependencies = [ - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-relations", - "ark-std 0.5.0", - "educe", - "num-bigint", - "num-integer", - "num-traits", - "tracing", -] - -[[package]] -name = "ark-relations" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" -dependencies = [ - "ark-ff 0.5.0", - "ark-std 0.5.0", - "tracing", - "tracing-subscriber", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -556,6 +527,19 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b" +dependencies = [ + "ark-serialize-derive 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "num-bigint", + "serde_with", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -579,15 +563,14 @@ dependencies = [ ] [[package]] -name = "ark-snark" -version = "0.5.1" +name = "ark-serialize-derive" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" +checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9" dependencies = [ - "ark-ff 0.5.0", - "ark-relations", - "ark-serialize 0.5.0", - "ark-std 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -597,7 +580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.8", ] [[package]] @@ -607,7 +590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.8", ] [[package]] @@ -617,14 +600,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155" +dependencies = [ + "num-traits", + "rand 0.8.8", ] [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "auto_impl" @@ -639,9 +632,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base16ct" @@ -649,11 +642,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bincode" @@ -687,15 +686,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -703,21 +702,6 @@ dependencies = [ "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 = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block-buffer" version = "0.10.4" @@ -728,28 +712,29 @@ dependencies = [ ] [[package]] -name = "borsh" -version = "1.5.7" +name = "block-buffer" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "borsh-derive", - "cfg_aliases", + "hybrid-array", ] [[package]] -name = "borsh-derive" -version = "1.5.7" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.119", + "tinyvec", ] +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + [[package]] name = "byte-slice-cast" version = "1.2.3" @@ -758,23 +743,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -784,18 +755,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.2.47" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" dependencies = [ "find-msvc-tools", "shlex", @@ -803,15 +774,21 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "chrono" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] [[package]] name = "clap" @@ -849,18 +826,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[package]] -name = "cobs" -version = "0.3.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.18", -] +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "colorchoice" @@ -876,12 +844,12 @@ checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" [[package]] name = "const-hex" -version = "1.17.0" +version = "1.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +checksum = "0e59eef12462b0f9b0a3620219be5d639afd79fe39dff0a42c3997061f9298b4" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -894,11 +862,12 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" dependencies = [ "const_format_proc_macros", + "konst", ] [[package]] @@ -913,13 +882,12 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "convert_case" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ - "core-foundation-sys", - "libc", + "unicode-segmentation", ] [[package]] @@ -929,21 +897,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "core-graphics-types" -version = "0.1.3" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "bitflags 1.3.2", - "core-foundation", "libc", ] [[package]] name = "cpufeatures" -version = "0.2.17" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] @@ -956,9 +922,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -966,18 +932,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -999,14 +965,54 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + [[package]] name = "der" version = "0.7.10" @@ -1017,6 +1023,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1030,21 +1045,23 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version 0.4.1", "syn 2.0.119", "unicode-xid", ] @@ -1064,23 +1081,27 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", - "crypto-common", + "crypto-common 0.1.7", "subtle", ] [[package]] -name = "doc-comment" -version = "0.3.4" +name = "digest" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", +] [[package]] -name = "downcast-rs" -version = "1.2.1" +name = "doc-comment" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] name = "dunce" @@ -1088,10 +1109,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "e3-bfv-client" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "anyhow", "e3-fhe-params", @@ -1105,8 +1131,7 @@ dependencies = [ [[package]] name = "e3-compute-provider" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -1118,17 +1143,17 @@ dependencies = [ "light-poseidon", "num-bigint", "num-traits", + "openvm-keccak256", "serde", "sha2", - "sha3", + "sha3 0.10.8", "thiserror 1.0.69", "zk-kit-imt", ] [[package]] name = "e3-fhe-params" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -1145,8 +1170,7 @@ dependencies = [ [[package]] name = "e3-parity-matrix" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "num-bigint", "num-traits", @@ -1156,8 +1180,7 @@ dependencies = [ [[package]] name = "e3-polynomial" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "fhe-math", "num-bigint", @@ -1168,14 +1191,16 @@ dependencies = [ [[package]] name = "e3-safe" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "risc0-bigint2", - "sha3", + "num-bigint", + "openvm", + "openvm-algebra-guest", + "serde", + "sha3 0.10.8", "taceo-poseidon2", ] @@ -1200,14 +1225,15 @@ dependencies = [ "e3-fhe-params", "fhe", "fhe-traits", + "openvm-keccak256", + "openvm-sha2", "sha2", - "sha3", + "sha3 0.10.8", ] [[package]] name = "e3-zk-helpers" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" +version = "0.15.2" dependencies = [ "anyhow", "ark-bn254 0.5.0", @@ -1262,15 +1288,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elf" -version = "0.7.4" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "elliptic-curve" @@ -1304,35 +1324,23 @@ dependencies = [ ] [[package]] -name = "embedded-io" -version = "0.4.0" +name = "enum-ordinalize" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] [[package]] -name = "embedded-io" -version = "0.6.1" +name = "enum-ordinalize-derive" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "enum-ordinalize" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.6", ] [[package]] @@ -1373,15 +1381,15 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" +checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fastrlp" @@ -1418,7 +1426,6 @@ dependencies = [ [[package]] name = "fhe" version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ "bincode", "doc-comment", @@ -1436,7 +1443,7 @@ dependencies = [ "rand_distr", "rayon", "serde", - "thiserror 2.0.18", + "thiserror 2.0.20", "zeroize", "zeroize_derive", ] @@ -1444,7 +1451,6 @@ dependencies = [ [[package]] name = "fhe-math" version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ "ethnum", "fhe-traits", @@ -1462,14 +1468,13 @@ dependencies = [ "serde", "sha2", "tfhe-ntt", - "thiserror 2.0.18", + "thiserror 2.0.20", "zeroize", ] [[package]] name = "fhe-traits" version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ "rand 0.9.2", ] @@ -1477,12 +1482,11 @@ dependencies = [ [[package]] name = "fhe-util" version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" dependencies = [ "num-bigint-dig", "num-traits", "prime_factorization", - "rand 0.8.5", + "rand 0.8.8", "rand 0.9.2", "rand_distr", "rayon", @@ -1490,9 +1494,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" [[package]] name = "fixed-hash" @@ -1501,7 +1505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.5", + "rand 0.8.8", "rustc-hex", "static_assertions", ] @@ -1531,43 +1535,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] -name = "foreign-types" -version = "0.5.0" +name = "funty" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] -name = "foreign-types-macros" -version = "0.2.3" +name = "futures-core" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] -name = "foreign-types-shared" -version = "0.3.1" +name = "futures-task" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] -name = "funty" -version = "2.0.0" +name = "futures-util" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1576,9 +1577,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", @@ -1593,10 +1594,21 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + [[package]] name = "group" version = "0.13.0" @@ -1609,15 +1621,10 @@ dependencies = [ ] [[package]] -name = "guests" -version = "0.1.0" -dependencies = [ - "bincode", - "e3-compute-provider", - "e3-support-types", - "e3-user-program", - "risc0-zkvm", -] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" @@ -1650,6 +1657,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "heck" version = "0.5.0" @@ -1662,12 +1675,6 @@ 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" @@ -1677,6 +1684,39 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "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 = "impl-codec" version = "0.6.0" @@ -1698,23 +1738,43 @@ dependencies = [ ] [[package]] -name = "include_bytes_aligned" -version = "0.1.4" +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] [[package]] name = "indexmap" -version = "2.12.1" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] +[[package]] +name = "interfold-openvm-guest" +version = "0.1.0" +dependencies = [ + "bincode", + "e3-compute-provider", + "e3-safe", + "e3-support-types", + "e3-user-program", + "openvm", + "openvm-algebra-guest", + "openvm-sha2", + "sha2", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1750,9 +1810,74 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] [[package]] name = "k256" @@ -1769,32 +1894,48 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", ] [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee" dependencies = [ "digest 0.10.7", "sha3-asm", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "konst" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" dependencies = [ - "spin", + "konst_macro_rules", ] +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "lean-imt" version = "0.1.2" @@ -1806,15 +1947,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "light-poseidon" @@ -1836,41 +1977,41 @@ checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" -version = "0.4.28" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] -name = "macro-string" -version = "0.1.4" +name = "lru" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "hashbrown 0.15.5", ] [[package]] -name = "malloc_buf" -version = "0.0.6" +name = "macro-string" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" dependencies = [ - "libc", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] name = "matrixmultiply" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" dependencies = [ "autocfg", "rawpointer", @@ -1878,36 +2019,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.6.4", - "zeroize", -] - -[[package]] -name = "metal" -version = "0.29.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" -dependencies = [ - "bitflags 2.10.0", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", -] +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "multimap" @@ -1931,12 +2045,6 @@ dependencies = [ "serde", ] -[[package]] -name = "no_std_strings" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" - [[package]] name = "num" version = "0.4.3" @@ -1959,7 +2067,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.5", + "rand 0.8.8", "serde", ] @@ -1989,26 +2097,58 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" dependencies = [ - "autocfg", "num-integer", "num-traits", ] +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-prime" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e238432a7881ec7164503ccc516c014bf009be7984cde1ba56837862543bdec3" +dependencies = [ + "bitvec", + "either", + "lru", + "num-bigint", + "num-integer", + "num-modular", + "num-traits", + "rand 0.8.8", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2031,20 +2171,73 @@ dependencies = [ ] [[package]] -name = "num_enum" -version = "0.7.5" +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openvm" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "num_enum_derive", - "rustversion", + "bytemuck", + "getrandom 0.2.17", + "getrandom 0.3.4", + "num-bigint", + "openvm-custom-insn", + "openvm-platform", + "openvm-rv32im-guest", + "serde", ] [[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +name = "openvm-algebra-complex-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-macros-common", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-algebra-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint", + "once_cell", + "openvm-algebra-complex-macros", + "openvm-algebra-moduli-macros", + "openvm-custom-insn", + "openvm-rv32im-guest", + "serde-big-array", + "strum_macros", +] + +[[package]] +name = "openvm-algebra-moduli-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint", + "num-prime", + "openvm-macros-common", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ "proc-macro2", "quote", @@ -2052,25 +2245,68 @@ dependencies = [ ] [[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +name = "openvm-keccak256" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-keccak256-guest", + "spin", + "tiny-keccak", +] + +[[package]] +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "malloc_buf", + "openvm-platform", ] [[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +name = "openvm-macros-common" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "syn 2.0.119", +] [[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "critical-section", + "embedded-alloc", + "libm", + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros", +] + +[[package]] +name = "openvm-sha2" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-sha2-guest", + "sha2", +] + +[[package]] +name = "openvm-sha2-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] [[package]] name = "parity-scale-codec" @@ -2108,9 +2344,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pest" -version = "2.8.4" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" dependencies = [ "memchr", "ucd-trie", @@ -2124,14 +2360,14 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.2", ] [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs8" @@ -2145,30 +2381,24 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" dependencies = [ "portable-atomic", ] [[package]] -name = "postcard" -version = "1.1.3" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -2197,7 +2427,7 @@ checksum = "bb24cb4f70d64221509ab3dca82ad2ec24e1d7f3fa3e7cb9eed4ced578683287" dependencies = [ "itertools 0.10.5", "num", - "rand 0.8.5", + "rand 0.8.8", ] [[package]] @@ -2213,30 +2443,30 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.7", + "toml_edit 0.25.15+spec-1.1.0", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "proc-macro-error-attr3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "82366fd7d8b7a440d66d13418820c69df9b3908bcb1a0476d7f5ce5d12f5a04d" dependencies = [ "proc-macro2", "quote", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "b511283ea8a74b4b39447b128c5d00f03a356b7424554b13e298a5550100d9ac" dependencies = [ - "proc-macro-error-attr2", + "proc-macro-error-attr3", "proc-macro2", "quote", "syn 2.0.119", @@ -2253,13 +2483,13 @@ dependencies = [ [[package]] name = "proptest" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.13.2", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -2323,9 +2553,9 @@ dependencies = [ [[package]] name = "pulp" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" dependencies = [ "bytemuck", "cfg-if", @@ -2340,9 +2570,9 @@ dependencies = [ [[package]] name = "pulp-wasm-simd-flag" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" [[package]] name = "quick-error" @@ -2365,6 +2595,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -2373,9 +2609,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -2389,7 +2625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -2410,7 +2646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2419,14 +2655,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", "serde", @@ -2448,7 +2684,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2457,7 +2693,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.2", ] [[package]] @@ -2493,236 +2729,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "risc0-bigint2" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87f5f7494a2242cead2750b7ce2b8522c1be83dee268479f1c12ed521eaf595" -dependencies = [ - "include_bytes_aligned", - "stability", -] - -[[package]] -name = "risc0-binfmt" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dca096030bb4c52f99b12abcfe3531ea93b17b95a12a5aeb06fbf8ee588a275" -dependencies = [ - "anyhow", - "borsh", - "bytemuck", - "derive_more", - "elf", - "lazy_static", - "postcard", - "rand 0.9.2", - "risc0-zkp", - "risc0-zkvm-platform", - "ruint", - "semver 1.0.27", - "serde", - "tracing", -] - -[[package]] -name = "risc0-circuit-keccak" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1d23ef3648bb85b0bd37bc9f9f7d13f1a4388e5e779e18f7eea82b969e5dbc" -dependencies = [ - "anyhow", - "bytemuck", - "paste", - "risc0-binfmt", - "risc0-circuit-recursion", - "risc0-core", - "risc0-zkp", - "tracing", -] - -[[package]] -name = "risc0-circuit-recursion" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028cd26e1b1f7bdd964d2f1eac8f812d1872b6b8fd24f10804f07d916b90000e" -dependencies = [ - "anyhow", - "bytemuck", - "hex", - "metal", - "risc0-core", - "risc0-zkp", - "tracing", -] - -[[package]] -name = "risc0-circuit-rv32im" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ecd73a71ddce62eab8a28552ee182dc2ea08cdce2a3474a616a80bf2d6e9be" -dependencies = [ - "anyhow", - "bit-vec", - "bytemuck", - "derive_more", - "paste", - "risc0-binfmt", - "risc0-core", - "risc0-zkp", - "serde", - "tracing", -] - -[[package]] -name = "risc0-core" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f2723fedace48c6c5a505bd8f97ac4e1712bc4cb769083e10536d862b66987" -dependencies = [ - "bytemuck", - "rand_core 0.9.3", -] - -[[package]] -name = "risc0-groth16" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ff13f9b427254c5264e01aaa32e33f355525299b6829449295905778f3b1e8" -dependencies = [ - "anyhow", - "ark-bn254 0.5.0", - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-groth16", - "ark-serialize 0.5.0", - "bytemuck", - "hex", - "num-bigint", - "num-traits", - "risc0-binfmt", - "risc0-zkp", - "serde", +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", ] [[package]] -name = "risc0-zkos-v1compat" -version = "2.2.1" +name = "ref-cast-impl" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf1f35f2ef61d8d86fdd06288c11d2f3bbf08f1af66b24ca0a1976ecbf324a1" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ - "include_bytes_aligned", - "no_std_strings", - "risc0-zkvm-platform", + "proc-macro2", + "quote", + "syn 3.0.6", ] [[package]] -name = "risc0-zkp" -version = "3.0.3" +name = "regex" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb493b3f007f04a11106a001c66bca77338d0fc375766189fd7ca3a1e8c3700" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ - "anyhow", - "blake2", - "borsh", - "bytemuck", - "cfg-if", - "digest 0.10.7", - "hex", - "hex-literal", - "metal", - "paste", - "rand_core 0.9.3", - "risc0-core", - "risc0-zkvm-platform", - "serde", - "sha2", - "stability", - "tracing", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "risc0-zkvm" -version = "3.0.3" +name = "regex-automata" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcce11648a9ff60b8e7af2f0ce7fbf8d25275ab6d414cc91b9da69ee75bc978" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ - "anyhow", - "borsh", - "bytemuck", - "derive_more", - "hex", - "risc0-binfmt", - "risc0-circuit-keccak", - "risc0-circuit-recursion", - "risc0-circuit-rv32im", - "risc0-core", - "risc0-groth16", - "risc0-zkos-v1compat", - "risc0-zkp", - "risc0-zkvm-platform", - "rrs-lib", - "semver 1.0.27", - "serde", - "sha2", - "stability", - "tracing", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "risc0-zkvm-platform" -version = "2.2.1" +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rfc6979" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "bytemuck", - "cfg-if", - "critical-section", - "embedded-alloc", - "getrandom 0.2.16", - "getrandom 0.3.4", - "libm", - "num_enum", - "paste", - "stability", + "hmac", + "subtle", ] [[package]] @@ -2747,27 +2809,17 @@ dependencies = [ "rustversion", ] -[[package]] -name = "rrs-lib" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" -dependencies = [ - "downcast-rs", - "paste", -] - [[package]] name = "ruint" -version = "1.17.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "2973657b5127d510e230f5c63d2d106af9c8f79393d8b9f4647323e8196bdde5" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "ark-ff 0.5.0", - "borsh", + "ark-ff 0.6.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -2777,7 +2829,7 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.5", + "rand 0.8.8", "rand 0.9.2", "rlp", "ruint-macro", @@ -2794,9 +2846,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc-hex" @@ -2819,16 +2871,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.27", + "semver 1.0.28", ] [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys", @@ -2837,9 +2889,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" @@ -2855,9 +2907,33 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] [[package]] name = "sec1" @@ -2884,13 +2960,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "semver-parser" @@ -2911,6 +2983,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -2953,6 +3034,26 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "time", +] + [[package]] name = "sha2" version = "0.10.9" @@ -2960,7 +3061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -2971,14 +3072,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", - "keccak", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.2", ] [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331" dependencies = [ "cc", "cfg-if", @@ -2986,9 +3097,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signature" @@ -3000,17 +3111,23 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "spin" -version = "0.9.8" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" [[package]] name = "spki" @@ -3022,16 +3139,6 @@ dependencies = [ "der", ] -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.119", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -3044,6 +3151,19 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[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.119", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3072,11 +3192,22 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn-solidity" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" +checksum = "eb6a2e3c7f7a3e4e83d1752cec5d1e357ced0cf96e85419b6a07f227db3def3a" dependencies = [ "paste", "proc-macro2", @@ -3105,12 +3236,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys", @@ -3138,11 +3269,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.20", ] [[package]] @@ -3158,13 +3289,43 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.6", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", ] [[package]] @@ -3176,6 +3337,12 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + [[package]] name = "toml" version = "0.8.23" @@ -3199,9 +3366,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -3212,33 +3379,33 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.14.2", "serde", "serde_spanned", "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.15", ] [[package]] name = "toml_edit" -version = "0.23.7" +version = "0.25.15+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" dependencies = [ - "indexmap", - "toml_datetime 0.7.3", + "indexmap 2.14.2", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow", + "winnow 1.0.4", ] [[package]] @@ -3247,53 +3414,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -3321,9 +3446,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-xid" @@ -3366,19 +3497,117 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -3390,18 +3619,27 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "wyz" @@ -3414,18 +3652,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.30" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.30" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" dependencies = [ "proc-macro2", "quote", @@ -3434,18 +3672,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", diff --git a/crates/support/openvm/guest/Cargo.toml b/crates/support/openvm/guest/Cargo.toml new file mode 100644 index 0000000000..1bc3671a20 --- /dev/null +++ b/crates/support/openvm/guest/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "interfold-openvm-guest" +version = "0.1.0" +edition = "2021" +license = "LGPL-3.0-only" + +[workspace] +resolver = "3" + +[dependencies] +openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", features = ["std", "heap-embedded-alloc"] } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +e3-support-types = { path = "../../types" } +e3-user-program = { path = "../../program", features = ["openvm-hashes"] } +e3-compute-provider = { path = "../../../compute-provider", features = ["openvm-hashes"] } +e3-safe = { path = "../../../safe", features = ["openvm"] } +bincode = "=1.3.3" +sha2 = "=0.10.9" + +[patch."https://github.com/gnosisguild/fhe.rs"] +fhe = { path = "../../../../target/openvm/fhe/crates/fhe" } +fhe-math = { path = "../../../../target/openvm/fhe/crates/fhe-math" } +fhe-traits = { path = "../../../../target/openvm/fhe/crates/fhe-traits" } +fhe-util = { path = "../../../../target/openvm/fhe/crates/fhe-util" } + +[profile.release] +lto = "fat" +codegen-units = 1 diff --git a/crates/support/openvm/guest/openvm.toml b/crates/support/openvm/guest/openvm.toml new file mode 100644 index 0000000000..d22f7699cf --- /dev/null +++ b/crates/support/openvm/guest/openvm.toml @@ -0,0 +1,7 @@ +[app_vm_config.rv32i] +[app_vm_config.rv32m] +[app_vm_config.io] +[app_vm_config.sha2] +[app_vm_config.keccak] +[app_vm_config.modular] +supported_moduli = ["21888242871839275222246405745257275088548364400416034343698204186575808495617"] diff --git a/crates/support/openvm/guest/src/main.rs b/crates/support/openvm/guest/src/main.rs new file mode 100644 index 0000000000..76a40b7eea --- /dev/null +++ b/crates/support/openvm/guest/src/main.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +openvm::init!(); + +use bincode::Options; +use e3_support_types::{ComputeGuestInput, ComputeJournal}; +use sha2::Digest; + +fn main() { + let bytes = openvm::io::read_vec(); + const MAX_BYTES: usize = 512 * 1024 * 1024 - 16; + assert!(bytes.len() <= MAX_BYTES, "The input exceeds the byte limit"); + let input: ComputeGuestInput = bincode::DefaultOptions::new() + .with_fixint_encoding() + .with_limit(MAX_BYTES as u64) + .reject_trailing_bytes() + .deserialize(&bytes) + .expect("Invalid compute input"); + assert!( + input.input.fhe_inputs.ciphertexts.len() <= 1024, + "Too many inputs" + ); + let (result, _) = input + .input + .run(e3_user_program::fhe_processor, e3_user_program::policy()) + .expect("Ciphertext aggregation failed"); + let journal = ComputeJournal::new(input.domain, result) + .expect("Invalid compute journal") + .abi_bytes() + .expect("Invalid journal encoding"); + let digest = openvm_sha2::Sha256::digest(&journal); + for (index, word) in digest.chunks_exact(4).enumerate() { + openvm::io::reveal_u32(u32::from_le_bytes(word.try_into().unwrap()), index); + } +} diff --git a/crates/support/openvm/prover/Cargo.lock b/crates/support/openvm/prover/Cargo.lock new file mode 100644 index 0000000000..5ff6d458f7 --- /dev/null +++ b/crates/support/openvm/prover/Cargo.lock @@ -0,0 +1,6516 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "abi_stable" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6512d3eb05ffe5004c59c206de7f99c34951504056ce23fc953842f12c445" +dependencies = [ + "abi_stable_derive", + "abi_stable_shared", + "const_panic", + "core_extensions", + "crossbeam-channel", + "generational-arena", + "libloading", + "lock_api", + "parking_lot", + "paste", + "repr_offset", + "rustc_version 0.4.1", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "abi_stable_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7178468b407a4ee10e881bc7a328a65e739f0863615cca4429d43916b05e898" +dependencies = [ + "abi_stable_shared", + "as_derive_utils", + "core_extensions", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 1.0.109", + "typed-arena", +] + +[[package]] +name = "abi_stable_shared" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63" +dependencies = [ + "core_extensions", +] + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror 2.0.20", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64579d931b3f8eacc7c9ab0b220e87e9c4816e5c724ede1947b55c2f8e92ae5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "k256", + "serde", + "thiserror 2.0.20", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "once_cell", + "serde", + "thiserror 2.0.20", +] + +[[package]] +name = "alloy-eips" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "borsh", + "c-kzg", + "derive_more 2.1.1", + "either", + "serde", + "serde_with", + "sha2 0.10.9", +] + +[[package]] +name = "alloy-json-abi" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "858acd7fdad1e4a7057fd9c1b39c1f2cd6bcd57ebf3c56e2853c02ead049e816" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-primitives" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5e9dbd49258ac3ab893a481d46be29b58be7f734dcac46cd80b6b13ee36566c" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 2.1.1", + "fixed-cache", + "foldhash 0.2.0", + "hashbrown 0.17.1", + "indexmap 2.14.2", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.9.5", + "rapidhash", + "ruint", + "rustc-hash 2.1.3", + "secp256k1", + "serde", + "sha3 0.11.0", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4311c03125e8a18296504560b9de3d75ecbd0dcda7f71e6cf2a196d57e6fba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "alloy-serde" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60dd79f578c3912f1fc2a150dbeb8110b8cfb976c60f98ebf6de9d5da5965a2b" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edb8520f2f94275e1caa73c85207dcc78ec402a9a4c429240f9a0783a8f16c0" +dependencies = [ + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.14.2", + "proc-macro-error3", + "proc-macro2", + "quote", + "sha3 0.11.0", + "syn 2.0.119", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66af2d9344882172993be5f5cbfd349fdfa52cb548f7af8715b446fb35ef6001" +dependencies = [ + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.119", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c2a8abc3334044013b23d5e438cc5dc802e5544cc42b713d0840d5185967cc" +dependencies = [ + "serde", + "winnow 1.0.4", +] + +[[package]] +name = "alloy-sol-types" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6f87cf007caa54e95455875fbd25879b008d0d9c7c340a2c258b3a3400a28c" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "serde", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +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 = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + +[[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", + "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", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af" +dependencies = [ + "ark-ff-asm 0.6.0", + "ark-ff-macros 0.6.0", + "ark-serialize 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "educe", + "num-bigint", + "num-traits", + "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-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-asm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "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", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", +] + +[[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", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b" +dependencies = [ + "ark-serialize-derive 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "num-bigint", + "serde_with", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as_derive_utils" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4" +dependencies = [ + "core_extensions", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "aurora-engine-modexp" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5188e264926edbd2e90d61bf8b33aa3471db8acdf427fa37946f9c82898fe502" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "serde", + "windows-link", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcode" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6ed1b54d8dc333e7be604d00fa9262f4635485ffea923647b6521a5fff045d" +dependencies = [ + "bytemuck", + "serde", +] + +[[package]] +name = "bitcoin-consensus-encoding" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6712f9c6fd6785b3b270884e57c441c403dc5d7e19ca45368c97c7a1de3000ec" +dependencies = [ + "bitcoin-internals", + "hex-conservative 1.3.0", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" + +[[package]] +name = "bitcoin-io" +version = "0.1.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78" +dependencies = [ + "bitcoin-consensus-encoding", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.3", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "serde", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3560a7b1951efe814fcd721938313adc56753ca39f4b23847d7e9a2402f5dbff" +dependencies = [ + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[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 = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[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 0.22.0", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "blst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff 0.13.1", + "group 0.13.0", + "pairing 0.23.0", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "bon" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60eafe0d77c3a2fc292c1d1346c3041b33c0a108085a2afabf672b70f69dbbc9" +dependencies = [ + "bon-macros", +] + +[[package]] +name = "bon-macros" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0f9631d8aaaee112c41985d675ef269e02acbd4f33122836af4f0c5f699ff6" +dependencies = [ + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b" + +[[package]] +name = "c-kzg" +version = "2.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d04308254695569fdb9bfe3bacc1c91837a670d0806605eb82d63748fbd3a6" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "camino" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +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.28", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cc" +version = "1.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.20", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "const-hex" +version = "1.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e59eef12462b0f9b0a3620219be5d639afd79fe39dff0a42c3997061f9298b4" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "proptest", + "serde_core", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "const_panic" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9603f79528ece8163c496f8932121cb36cfe46259e9c907bb3d8205139d7caa3" +dependencies = [ + "typewit", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_extensions" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42bb5e5d0269fd4f739ea6cedaf29c16d81c27a7ce7582008e90eb50dcd57003" +dependencies = [ + "core_extensions_proc_macros", +] + +[[package]] +name = "core_extensions_proc_macros" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533d38ecd2709b7608fb8e18e4504deb99e9a72879e6aa66373a76d8dc4259ea" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71406cd8807725f7ac2f999a4cdd32e98f829fdf65f528343cebf945e41df1e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "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", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctor" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" + +[[package]] +name = "darling" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 3.0.6", +] + +[[package]] +name = "darling_macro" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" +dependencies = [ + "darling_core", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", + "rayon", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[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-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive-where" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2b94854e8576378ccda7c8de8a66ed8b4e8acbd2c50ec3418ea6c8aaf4b567" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dtor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[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 = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[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.1", + "generic-array", + "group 0.13.0", + "pkcs8", + "rand_core 0.6.4", + "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 = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "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", + "primitive-types", + "uint", +] + +[[package]] +name = "eyre" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08309dbcc659c5549a24ddb9b27027640641b282ef5768267c7e675558986a3" +dependencies = [ + "autocfg", + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[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 = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +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 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" + +[[package]] +name = "fixed-cache" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fe63500644ef0269fe6b744e7e5dc5c20b5eebf3d881bc2be53f194636f6583" +dependencies = [ + "equivalent", + "rapidhash", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.8", + "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 = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "getset" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "gmp-mpfr-sys" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db155b537cb791b133341f99f68371d86ee7fa4c79aacfbc376d72d23c70531" +dependencies = [ + "libc", + "windows-sys", +] + +[[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 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.1", + "rand 0.8.8", + "rand_core 0.6.4", + "rand_xorshift 0.3.0", + "subtle", +] + +[[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-axiom" +version = "0.5.3" +source = "git+https://github.com/axiom-crypto/halo2.git?tag=v0.5.3#5e4f0e524956f23b50d51b3a2f7bb07834948598" +dependencies = [ + "blake2b_simd", + "crossbeam", + "ff 0.13.1", + "group 0.13.0", + "halo2curves-axiom", + "itertools 0.11.0", + "maybe-rayon", + "pairing 0.23.0", + "rand 0.8.8", + "rand_core 0.6.4", + "rayon", + "rustc-hash 1.1.0", + "sha3 0.10.9", + "tracing", +] + +[[package]] +name = "halo2-base" +version = "0.5.5" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.5#e08c6cb7020a53ded1c912a5ca1cf4101a942a20" +dependencies = [ + "getset", + "halo2-axiom", + "itertools 0.11.0", + "log", + "num-bigint", + "num-integer", + "num-traits", + "poseidon-primitives", + "rand_chacha 0.3.1", + "rayon", + "rustc-hash 1.1.0", + "serde", + "serde_json", +] + +[[package]] +name = "halo2-ecc" +version = "0.5.5" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.5#e08c6cb7020a53ded1c912a5ca1cf4101a942a20" +dependencies = [ + "halo2-base", + "itertools 0.11.0", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.8.8", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "rayon", + "serde", + "serde_json", + "test-case", +] + +[[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 0.6.4", + "rayon", +] + +[[package]] +name = "halo2curves-axiom" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276d6c463e0e8e70c1a221baae62b670453f6ef851dd1c73f0764e5215fda64d" +dependencies = [ + "blake2b_simd", + "digest 0.10.7", + "ff 0.13.1", + "group 0.13.0", + "hex", + "lazy_static", + "num-bigint", + "num-traits", + "pairing 0.23.0", + "pasta_curves 0.5.2", + "paste", + "rand 0.8.8", + "rand_core 0.6.4", + "rayon", + "serde", + "serde_arrays", + "sha2 0.10.9", + "static_assertions", + "subtle", + "unroll", +] + +[[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", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[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.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3fef046dca3ca91ee1408a8c1b80ab777e80a4d308d1bf4e7adb3fcb047e08" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-conservative" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271e0d19bcb473b6675739a2b536076b24a082316cb5199ad918edce10c599e8" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + +[[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 = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "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 = "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-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[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.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "interfold-openvm-prover" +version = "0.1.0" +dependencies = [ + "eyre", + "hex", + "openvm-circuit", + "openvm-sdk", + "openvm-sdk-config", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[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.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +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 = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[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 0.6.4", + "subtle", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", +] + +[[package]] +name = "keccak-asm" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.9", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.8", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "macro-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memuse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" + +[[package]] +name = "metrics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3045b4193fbdc5b5681f32f11070da9be3609f189a79f3390706d42587f46bb5" +dependencies = [ + "ahash", + "portable-atomic", +] + +[[package]] +name = "metrics-tracing-context" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a6a1f7141f1d9bc7a886b87536bbfc97752e08b369e1e0453a9acfab5f5da4" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "lockfree-object-pool", + "metrics", + "metrics-util", + "once_cell", + "tracing", + "tracing-core", + "tracing-subscriber 0.3.23", +] + +[[package]] +name = "metrics-util" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4259040465c955f9f2f1a4a8a16dc46726169bca0f88e8fb2dbeced487c3e828" +dependencies = [ + "aho-corasick", + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.14.5", + "indexmap 2.14.2", + "metrics", + "num_cpus", + "ordered-float", + "quanta", + "radix_trie", + "sketches-ddsketch", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.8.8", + "serde", +] + +[[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.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-prime" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e238432a7881ec7164503ccc516c014bf009be7984cde1ba56837862543bdec3" +dependencies = [ + "bitvec", + "either", + "lru", + "num-bigint", + "num-integer", + "num-modular", + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "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.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nvtx" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2e855e8019f99e4b94ac33670eb4e4f570a2e044f3749a0b2c7f83b841e52c" +dependencies = [ + "cc", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openvm" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "bytemuck", + "num-bigint", + "openvm-custom-insn", + "openvm-platform", + "openvm-rv32im-guest", + "serde", +] + +[[package]] +name = "openvm-algebra-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "blstrs", + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "halo2curves-axiom", + "num-bigint", + "num-traits", + "once_cell", + "openvm-algebra-transpiler", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-instructions", + "openvm-mod-circuit-builder", + "openvm-rv32-adapters", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", + "serde_with", + "strum", +] + +[[package]] +name = "openvm-algebra-complex-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-macros-common", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-algebra-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "halo2curves-axiom", + "num-bigint", + "once_cell", + "openvm-algebra-complex-macros", + "openvm-algebra-moduli-macros", + "openvm-custom-insn", + "openvm-rv32im-guest", + "serde-big-array", + "strum_macros", +] + +[[package]] +name = "openvm-algebra-moduli-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint", + "num-prime", + "openvm-macros-common", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-algebra-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-algebra-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-bigint-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "openvm-bigint-transpiler", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-instructions", + "openvm-rv32-adapters", + "openvm-rv32im-circuit", + "openvm-rv32im-transpiler", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", +] + +[[package]] +name = "openvm-bigint-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", + "strum_macros", +] + +[[package]] +name = "openvm-bigint-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-bigint-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-rv32im-transpiler", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-build" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cargo_metadata", + "eyre", + "openvm-platform", + "serde", + "serde_json", +] + +[[package]] +name = "openvm-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "abi_stable", + "backtrace", + "bytesize", + "cfg-if", + "dashmap", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "getset", + "itertools 0.14.0", + "libc", + "memmap2", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-instructions", + "openvm-poseidon2-air", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-baby-bear", + "p3-field", + "rand 0.9.5", + "rustc-hash 2.1.3", + "serde", + "serde-big-array", + "static_assertions", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-circuit-derive" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-circuit-primitives" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "derive-new 0.6.0", + "itertools 0.14.0", + "num-bigint", + "num-traits", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-stark-backend", + "rand 0.9.5", + "struct-reflection", + "tracing", +] + +[[package]] +name = "openvm-circuit-primitives-derive" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-codec-derive" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-continuations" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "derivative", + "derive-new 0.6.0", + "eyre", + "hex", + "itertools 0.14.0", + "num-bigint", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", + "p3-bn254", + "p3-field", + "p3-matrix", + "serde", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-cpu-backend" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "cfg-if", + "derive-new 0.7.0", + "getset", + "itertools 0.14.0", + "openvm-stark-backend", + "p3-air", + "p3-baby-bear", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "rayon", + "rustc-hash 2.1.3", + "serde", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-cuda-backend" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "derive-new 0.7.0", + "getset", + "glob", + "itertools 0.14.0", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-baby-bear", + "p3-bn254", + "p3-dft", + "p3-field", + "p3-symmetric", + "p3-util", + "rand 0.9.5", + "rustc-hash 2.1.3", + "serde", + "thiserror 1.0.69", + "tracing", + "zkhash-axiom", +] + +[[package]] +name = "openvm-cuda-builder" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "cc", + "glob", +] + +[[package]] +name = "openvm-cuda-common" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "bytesize", + "ctor", + "lazy_static", + "metrics", + "openvm-cuda-builder", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-deferral-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "dashmap", + "derive-new 0.6.0", + "derive_more 1.0.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-deferral-transpiler", + "openvm-instructions", + "openvm-poseidon2-air", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "rand 0.9.5", + "rustc-hash 2.1.3", + "serde", +] + +[[package]] +name = "openvm-deferral-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros", +] + +[[package]] +name = "openvm-deferral-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "eyre", + "openvm-deferral-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-transpiler", + "p3-field", + "rrs-lib", + "serde", + "strum", +] + +[[package]] +name = "openvm-ecc-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "blstrs", + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "halo2curves-axiom", + "hex-literal", + "lazy_static", + "num-bigint", + "num-traits", + "once_cell", + "openvm-algebra-circuit", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-ecc-transpiler", + "openvm-instructions", + "openvm-mod-circuit-builder", + "openvm-rv32-adapters", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", + "serde_with", + "strum", +] + +[[package]] +name = "openvm-ecc-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "ecdsa", + "elliptic-curve", + "group 0.13.0", + "halo2curves-axiom", + "once_cell", + "openvm", + "openvm-algebra-guest", + "openvm-custom-insn", + "openvm-ecc-sw-macros", + "openvm-rv32im-guest", + "serde", + "strum_macros", +] + +[[package]] +name = "openvm-ecc-sw-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-macros-common", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-ecc-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-ecc-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-instructions" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "backtrace", + "derive-new 0.6.0", + "itertools 0.14.0", + "num-bigint", + "num-traits", + "openvm-instructions-derive", + "openvm-stark-backend", + "serde", + "strum", + "strum_macros", +] + +[[package]] +name = "openvm-instructions-derive" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-keccak256-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "derive-new 0.6.0", + "derive_more 1.0.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-instructions", + "openvm-keccak256-transpiler", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-keccak-air", + "rand 0.9.5", + "serde", + "strum", + "tiny-keccak", +] + +[[package]] +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-keccak256-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-instructions", + "openvm-instructions-derive", + "openvm-keccak256-guest", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-macros-common" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "syn 2.0.119", +] + +[[package]] +name = "openvm-mod-circuit-builder" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "itertools 0.14.0", + "num-bigint", + "num-traits", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-instructions", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.8.8", + "rand 0.9.5", + "tracing", +] + +[[package]] +name = "openvm-pairing-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "halo2curves-axiom", + "num-bigint", + "num-traits", + "openvm-algebra-circuit", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-ecc-circuit", + "openvm-ecc-guest", + "openvm-instructions", + "openvm-mod-circuit-builder", + "openvm-pairing-guest", + "openvm-pairing-transpiler", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", + "strum", +] + +[[package]] +name = "openvm-pairing-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "blstrs", + "halo2curves-axiom", + "hex-literal", + "itertools 0.14.0", + "lazy_static", + "num-bigint", + "num-traits", + "openvm", + "openvm-algebra-guest", + "openvm-algebra-moduli-macros", + "openvm-custom-insn", + "openvm-ecc-guest", + "serde", + "strum_macros", +] + +[[package]] +name = "openvm-pairing-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-instructions", + "openvm-pairing-guest", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "libm", + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-poseidon2-air" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "derivative", + "lazy_static", + "openvm-circuit-primitives", + "openvm-cuda-builder", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-poseidon2", + "p3-poseidon2-air", + "p3-symmetric", + "rand 0.9.5", + "zkhash-axiom", +] + +[[package]] +name = "openvm-recursion-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "derive-new 0.6.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-air", + "p3-baby-bear", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "strum", + "strum_macros", + "tracing", +] + +[[package]] +name = "openvm-recursion-circuit-derive" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openvm-rv32-adapters" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "derive-new 0.6.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-instructions", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", +] + +[[package]] +name = "openvm-rv32im-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "num-bigint", + "num-integer", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-instructions", + "openvm-rv32im-transpiler", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", + "strum", + "tracing", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros", +] + +[[package]] +name = "openvm-rv32im-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-instructions", + "openvm-instructions-derive", + "openvm-rv32im-guest", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "serde", + "strum", + "tracing", +] + +[[package]] +name = "openvm-sdk" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "alloy-sol-types", + "bitcode", + "cfg-if", + "clap", + "derivative", + "derive-new 0.6.0", + "derive_more 1.0.0", + "eyre", + "getset", + "halo2-base", + "hex", + "itertools 0.14.0", + "openvm", + "openvm-build", + "openvm-circuit", + "openvm-continuations", + "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-recursion-circuit", + "openvm-sdk-config", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-transpiler", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", + "serde", + "serde_json", + "serde_with", + "tempfile", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-sdk-config" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "bon", + "cfg-if", + "derive_more 1.0.0", + "openvm-algebra-circuit", + "openvm-algebra-transpiler", + "openvm-bigint-circuit", + "openvm-bigint-transpiler", + "openvm-circuit", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-deferral-transpiler", + "openvm-ecc-circuit", + "openvm-ecc-transpiler", + "openvm-keccak256-circuit", + "openvm-keccak256-transpiler", + "openvm-pairing-circuit", + "openvm-pairing-transpiler", + "openvm-rv32im-circuit", + "openvm-rv32im-transpiler", + "openvm-sha2-circuit", + "openvm-sha2-transpiler", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-transpiler", + "openvm-verify-stark-circuit", + "serde", + "toml", +] + +[[package]] +name = "openvm-sha2-air" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "ndarray", + "num_enum", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-stark-backend", + "rand 0.9.5", + "sha2 0.10.9", +] + +[[package]] +name = "openvm-sha2-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "cfg-if", + "derive-new 0.6.0", + "derive_more 1.0.0", + "itertools 0.14.0", + "ndarray", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-instructions", + "openvm-rv32im-circuit", + "openvm-sha2-air", + "openvm-sha2-transpiler", + "openvm-stark-backend", + "openvm-stark-sdk", + "rand 0.9.5", + "serde", + "sha2 0.10.9", +] + +[[package]] +name = "openvm-sha2-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-sha2-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-instructions", + "openvm-instructions-derive", + "openvm-sha2-guest", + "openvm-stark-backend", + "openvm-transpiler", + "rrs-lib", + "strum", +] + +[[package]] +name = "openvm-stark-backend" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "cfg-if", + "derivative", + "derive-new 0.7.0", + "eyre", + "getset", + "hex-literal", + "itertools 0.14.0", + "num-bigint", + "openvm-codec-derive", + "p3-air", + "p3-challenger", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "postcard", + "rayon", + "rustc-hash 2.1.3", + "serde", + "serde_json", + "thiserror 1.0.69", + "tikv-jemallocator", + "tracing", +] + +[[package]] +name = "openvm-stark-sdk" +version = "2.0.1" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.1#362c7ad8c6b042b320471a137e3eadec7ec69a44" +dependencies = [ + "dashmap", + "derive-new 0.7.0", + "eyre", + "hex-literal", + "itertools 0.14.0", + "metrics-tracing-context", + "metrics-util", + "num-bigint", + "nvtx", + "openvm-cpu-backend", + "openvm-stark-backend", + "p3-baby-bear", + "p3-bn254", + "p3-field", + "p3-poseidon2", + "rand 0.9.5", + "serde", + "serde_json", + "static_assertions", + "tracing", + "tracing-forest", + "tracing-subscriber 0.3.23", + "zkhash-axiom", +] + +[[package]] +name = "openvm-static-verifier" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "halo2-base", + "itertools 0.14.0", + "num-bigint", + "num-integer", + "once_cell", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-recursion-circuit", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "serde_with", + "snark-verifier-sdk", + "tracing", +] + +[[package]] +name = "openvm-transpiler" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "elf", + "eyre", + "openvm-instructions", + "openvm-platform", + "openvm-stark-backend", + "rrs-lib", + "thiserror 1.0.69", +] + +[[package]] +name = "openvm-verify-stark-circuit" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "bitcode", + "cfg-if", + "derive-new 0.6.0", + "eyre", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-deferral-circuit", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", + "p3-field", + "p3-matrix", + "serde", + "tracing", +] + +[[package]] +name = "openvm-verify-stark-host" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "bitcode", + "eyre", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "serde", + "thiserror 1.0.69", + "zstd", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "p3-air" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daee3082e2ca0db2ac876c43c9c8fd53204b0fcb95cfe7258d21f4a925ad82c4" +dependencies = [ + "p3-field", + "p3-matrix", +] + +[[package]] +name = "p3-baby-bear" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1a49f4d9c8b8cbdab61e25d9de1b78b3c8347dd2fb88b11d990b3efa8cdd3a" +dependencies = [ + "p3-challenger", + "p3-field", + "p3-mds", + "p3-monty-31", + "p3-poseidon2", + "p3-symmetric", + "rand 0.9.5", +] + +[[package]] +name = "p3-bn254" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923bd91df7dd93481b4bfb53aa903d46d1a49d51160513472a5e95ca92ef1b46" +dependencies = [ + "num-bigint", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "paste", + "rand 0.9.5", + "serde", +] + +[[package]] +name = "p3-challenger" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d2d45f5a51dc3f965e8d6da60a6c26c807e88657863d56da275eaa05ad36f1" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-monty-31", + "p3-symmetric", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-dft" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beabb40bc8ac7f5f95870f271fb844c7e2e1ebb7f0761a8eebb2614b56c6b1c1" +dependencies = [ + "itertools 0.14.0", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "spin 0.10.1", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4819a3e4c1882431a63d4847ffa10d110017aee4cb9cf4319ca6dca191930969" +dependencies = [ + "itertools 0.14.0", + "num-bigint", + "p3-maybe-rayon", + "p3-util", + "paste", + "rand 0.9.5", + "serde", + "tracing", +] + +[[package]] +name = "p3-interpolation" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27a3696641a8f4ec990ff8c91862fb4f3b4ff29f589f78005d046023fe3550f" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", +] + +[[package]] +name = "p3-keccak-air" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4832d817455f7a4a35b598cbb8a42f1ee0430ee82df0203956c26917b2509865" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "rand 0.9.5", + "tracing", +] + +[[package]] +name = "p3-matrix" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6fde449bd2963d394284ec46db8c647e6a5602d90601117b76752072ab54168" +dependencies = [ + "itertools 0.14.0", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand 0.9.5", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54afab3883d8a14676b492709d6c4e9fa535c36718b737db0817aacfaaaa11f6" +dependencies = [ + "rayon", +] + +[[package]] +name = "p3-mds" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3895055d735ac96d010747b3aaabd4c2645b9fd80226960550318db2e25afb75" +dependencies = [ + "p3-dft", + "p3-field", + "p3-symmetric", + "p3-util", + "rand 0.9.5", +] + +[[package]] +name = "p3-monty-31" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fe0be661891af1f703ceaf57334fcbd540804988984dc2b500dd99740e7c81" +dependencies = [ + "itertools 0.14.0", + "num-bigint", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "paste", + "rand 0.9.5", + "serde", + "spin 0.10.1", + "tracing", +] + +[[package]] +name = "p3-poseidon2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6fc2368447576283f8b3849a36095017f25addf06eab9e33b0ce7f96b0b99d" +dependencies = [ + "p3-field", + "p3-mds", + "p3-symmetric", + "p3-util", + "rand 0.9.5", +] + +[[package]] +name = "p3-poseidon2-air" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a80481b023f74c0f8ded5058dab8054174e8060d82d400da7b67cf7f2f0a87bc" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-poseidon2", + "rand 0.9.5", + "tracing", +] + +[[package]] +name = "p3-symmetric" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a14456a42a7d9e65f13999706f1bca2832175935169b3a54286e18331cf1d82f" +dependencies = [ + "itertools 0.14.0", + "p3-field", + "serde", +] + +[[package]] +name = "p3-util" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911154accf66034b0eec4452956c088f92a200b37a8225c1caed74cfbd38cc8d" +dependencies = [ + "serde", + "transpose", +] + +[[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 = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group 0.13.0", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[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 0.8.8", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3437083215c505e867eea5478371feba43d7689d6d15ec0a209eb46fb0d4cda6" +dependencies = [ + "blake2b_simd", + "ff 0.13.1", + "group 0.13.0", + "lazy_static", + "rand 0.8.8", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.8", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[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.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "poseidon-primitives" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4aaeda7a092e21165cc5f0cbc738e72a46f31c03c3cbd87b71ceae9d2d93bc" +dependencies = [ + "bitvec", + "ff 0.13.1", + "lazy_static", + "log", + "rand 0.8.8", + "rand_xorshift 0.3.0", + "thiserror 1.0.69", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" +dependencies = [ + "proc-macro2", + "syn 3.0.6", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[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", + "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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.15+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error-attr3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82366fd7d8b7a440d66d13418820c69df9b3908bcb1a0476d7f5ce5d12f5a04d" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b511283ea8a74b4b39447b128c5d00f03a356b7424554b13e298a5550100d9ac" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bitflags 2.13.2", + "num-traits", + "rand 0.9.5", + "rand_chacha 0.9.0", + "rand_xorshift 0.4.0", + "regex-syntax", + "unarray", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "repr_offset" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea" +dependencies = [ + "tstr", +] + +[[package]] +name = "revm" +version = "27.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6bf82101a1ad8a2b637363a37aef27f88b4efc8a6e24c72bf5f64923dc5532" +dependencies = [ + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", +] + +[[package]] +name = "revm-bytecode" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c52031b73cae95d84cd1b07725808b5fd1500da3e5e24574a3b2dc13d9f16d" +dependencies = [ + "bitvec", + "phf", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-context" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" +dependencies = [ + "cfg-if", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-context-interface" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc90302642d21c8f93e0876e201f3c5f7913c4fcb66fb465b0fd7b707dfe1c79" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" +dependencies = [ + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-database-interface" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c523c77e74eeedbac5d6f7c092e3851dbe9c7fec6f418b85992bd79229db361" +dependencies = [ + "auto_impl", + "either", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-handler" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1529c8050e663be64010e80ec92bf480315d21b1f2dbf65540028653a621b27d" +dependencies = [ + "auto_impl", + "derive-where", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", + "serde", +] + +[[package]] +name = "revm-inspector" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78db140e332489094ef314eaeb0bd1849d6d01172c113ab0eb6ea8ab9372926" +dependencies = [ + "auto_impl", + "either", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", + "serde", + "serde_json", +] + +[[package]] +name = "revm-interpreter" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff9d7d9d71e8a33740b277b602165b6e3d25fff091ba3d7b5a8d373bf55f28a7" +dependencies = [ + "revm-bytecode", + "revm-context-interface", + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-precompile" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cee3f336b83621294b4cfe84d817e3eef6f3d0fce00951973364cc7f860424d" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayref", + "aurora-engine-modexp", + "blst", + "c-kzg", + "cfg-if", + "k256", + "libsecp256k1", + "once_cell", + "p256", + "revm-primitives", + "ripemd", + "rug", + "secp256k1", + "sha2 0.10.9", +] + +[[package]] +name = "revm-primitives" +version = "20.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa29d9da06fe03b249b6419b33968ecdf92ad6428e2f012dc57bcd619b5d94e" +dependencies = [ + "alloy-primitives", + "num_enum", + "once_cell", + "serde", +] + +[[package]] +name = "revm-state" +version = "7.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" +dependencies = [ + "bitflags 2.13.2", + "revm-bytecode", + "revm-primitives", + "serde", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[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", + "rustc-hex", +] + +[[package]] +name = "rrs-lib" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" +dependencies = [ + "downcast-rs", + "paste", +] + +[[package]] +name = "rug" +version = "1.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07a8857882aec59d27254b02481c709327c13de6fad1da60bfc4f9783eaaa61e" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", +] + +[[package]] +name = "ruint" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2973657b5127d510e230f5c63d2d106af9c8f79393d8b9f4647323e8196bdde5" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "ark-ff 0.6.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.8", + "rand 0.9.5", + "rlp", + "ruint-macro", + "serde_core", + "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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[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.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.28", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + +[[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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_with" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "935177bb8c0cd8ca1a4e6d1a2ac8988bea69cab4f9d3a31311e012ad27868ea4" +dependencies = [ + "base64 0.23.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d607aa01a3cb0ad757d6fd216136910db3c97b102fe686585689615a02dbcdc" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest 0.10.7", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.2", +] + +[[package]] +name = "sha3-asm" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331" +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 = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[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 0.6.4", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "sketches-ddsketch" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "snark-verifier" +version = "0.2.7" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.7#6adabb60fa1779567dd45e8f01d6277a6c34e87e" +dependencies = [ + "halo2-base", + "halo2-ecc", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "pairing 0.23.0", + "rand 0.8.8", + "revm", + "ruint", + "serde", + "sha3 0.10.9", +] + +[[package]] +name = "snark-verifier-sdk" +version = "0.2.7" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.7#6adabb60fa1779567dd45e8f01d6277a6c34e87e" +dependencies = [ + "bincode", + "ethereum-types", + "getset", + "halo2-base", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.8.8", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "snark-verifier", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" + +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "struct-reflection" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "701b671d1ad68e250e05718f95dae3014a17f4e69cbe51842531c30495ff3301" +dependencies = [ + "struct-reflection-derive", +] + +[[package]] +name = "struct-reflection-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ab74230a0592602e361bd63c645413fa8cbe4500d10274e849179e5c72548f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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.119", +] + +[[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.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6a2e3c7f7a3e4e83d1752cec5d1e357ced0cf96e85419b6a07f227db3def3a" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "test-case-core", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +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.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.2", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.2", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.15+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +dependencies = [ + "indexmap 2.14.2", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +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 1.0.69", + "tracing", + "tracing-subscriber 0.3.23", +] + +[[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.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "tstr" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8e0294f14baae476d0dd0a2d780b2e24d66e349a9de876f5126777a37bdba7" +dependencies = [ + "tstr_proc_macros", +] + +[[package]] +name = "tstr_proc_macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "typewit" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[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-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unroll" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[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.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[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.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zkhash-axiom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d038a7895d0e3ab0a352f53e7eb4f1f829f88fce2fb3cff93d665a8a0e01af6" +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.2", + "rand 0.8.8", + "serde", + "sha2 0.10.9", + "sha3 0.10.9", + "subtle", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.0+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/crates/support/openvm/prover/Cargo.toml b/crates/support/openvm/prover/Cargo.toml new file mode 100644 index 0000000000..a36d46440c --- /dev/null +++ b/crates/support/openvm/prover/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "interfold-openvm-prover" +version = "0.1.0" +edition = "2021" +license = "LGPL-3.0-only" + +[workspace] +resolver = "3" + +[features] +cuda = ["openvm-sdk/cuda"] + +[dependencies] +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", default-features = false, features = ["parallel", "evm-verify"] } +openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +sha2 = "=0.10.9" +eyre = "0.6" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +hex = "0.4" diff --git a/crates/support/openvm/prover/src/main.rs b/crates/support/openvm/prover/src/main.rs new file mode 100644 index 0000000000..5de7c1054d --- /dev/null +++ b/crates/support/openvm/prover/src/main.rs @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +use eyre::{ensure, Result}; +use openvm_circuit::arch::instructions::exe::VmExe; +use openvm_sdk::{ + config::AggregationSystemParams, + fs::{read_halo2_pk_from_file, read_object_from_file, write_object_to_file}, + keygen::{AggProvingKey, AppProvingKey}, + types::{AppExecutionCommit, EvmHalo2Verifier, EvmProof}, + Sdk, StdIn, F, +}; +use openvm_sdk_config::SdkVmConfig; +use serde::Deserialize; +use sha2::{Digest, Sha256}; +use std::{ + fs, + io::{Read, Write}, + path::{Path, PathBuf}, +}; + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct Config { + app_pk: PathBuf, + executable: PathBuf, + aggregation_pk: PathBuf, + halo2_pk: PathBuf, + halo2_params_dir: PathBuf, + verifier_artifact: PathBuf, + verifier_sha256: String, + app_commit: AppExecutionCommit, + segment_memory_bytes: usize, +} + +fn read_limited(path: &Path, limit: usize) -> Result> { + let mut bytes = Vec::new(); + fs::File::open(path)? + .take(limit as u64 + 1) + .read_to_end(&mut bytes)?; + ensure!(bytes.len() <= limit, "The artifact exceeds its size limit"); + Ok(bytes) +} + +fn config(path: &Path) -> Result { + let config: Config = serde_json::from_slice(&read_limited(path, 64 * 1024)?)?; + for path in [ + &config.app_pk, + &config.executable, + &config.aggregation_pk, + &config.halo2_pk, + &config.verifier_artifact, + ] { + ensure!( + path.is_absolute() && path.is_file(), + "Each artifact path must name an existing absolute file path" + ); + } + ensure!( + config.halo2_params_dir.is_absolute() && config.halo2_params_dir.is_dir(), + "The Halo2 parameter path must name an existing absolute directory" + ); + ensure!( + config.segment_memory_bytes > 0, + "Set a nonzero segment memory limit" + ); + Ok(config) +} + +fn verifier(config: &Config) -> Result { + let bytes = read_limited(&config.verifier_artifact, 256 * 1024)?; + ensure!( + hex::encode(Sha256::digest(&bytes)) == config.verifier_sha256, + "The verifier artifact does not match the configured SHA-256 digest" + ); + Ok(EvmHalo2Verifier { + artifact: serde_json::from_slice(&bytes)?, + halo2_verifier_code: String::new(), + openvm_verifier_code: String::new(), + openvm_verifier_interface: String::new(), + }) +} + +fn sdk(config: &Config) -> Result<(Sdk, VmExe)> { + let mut app_pk: AppProvingKey = read_object_from_file(&config.app_pk)?; + std::sync::Arc::get_mut(&mut app_pk.app_vm_pk) + .unwrap() + .vm_config + .system + .config + .segmentation_max_memory = config.segment_memory_bytes; + let exe: VmExe = read_object_from_file(&config.executable)?; + let aggregation_key: AggProvingKey = read_object_from_file(&config.aggregation_pk)?; + let derived = Sdk::builder() + .app_pk(app_pk.clone()) + .agg_params(AggregationSystemParams { + leaf: aggregation_key.prefix.leaf.params.clone(), + internal: aggregation_key.prefix.internal_for_leaf.params.clone(), + }) + .build()?; + ensure!( + serde_json::to_value(derived.agg_pk())? == serde_json::to_value(&aggregation_key)?, + "The aggregation key does not match the application VM" + ); + drop(derived); + let sdk = Sdk::builder() + .app_pk(app_pk) + .agg_pk(aggregation_key) + .halo2_params_dir(&config.halo2_params_dir) + .build()?; + let prover = sdk.prover(exe.clone())?; + let baseline = prover.generate_baseline(); + let expected = AppExecutionCommit { + app_exe_commit: baseline.app_exe_commit.into(), + app_vm_commit: prover.app_vm_commit().into(), + }; + ensure!( + expected == config.app_commit, + "The executable or VM commitment differs from the configured identity" + ); + Ok((sdk, exe)) +} + +fn verify(proof: &EvmProof, config: &Config, journal: &[u8]) -> Result<()> { + ensure!(proof.version == "v2.0", "Unsupported OpenVM proof version"); + ensure!(journal.len() == 288, "Expected nine journal words"); + ensure!( + proof.app_commit == config.app_commit, + "The application commitment differs" + ); + ensure!( + proof.user_public_values == Sha256::digest(journal).to_vec(), + "The proof public values do not match the journal" + ); + ensure!( + proof.proof_data.accumulator.len() == 384 && proof.proof_data.proof.len() == 1376, + "The proof data has an invalid length" + ); + Sdk::verify_evm_halo2_proof( + &verifier(config)?, + proof.clone(), + Some(config.app_commit.clone()), + )?; + Ok(()) +} + +fn word(value: usize) -> [u8; 32] { + let mut bytes = [0; 32]; + bytes[24..].copy_from_slice(&(value as u64).to_be_bytes()); + bytes +} + +/// Encode a verified receipt as (version, proof data, nine journal words). +fn seal(proof: &EvmProof, journal: &[u8]) -> Vec { + let mut bytes = Vec::with_capacity(2144); + bytes.extend_from_slice(&word(1)); + bytes.extend_from_slice(&word(352)); + bytes.extend_from_slice(journal); + bytes.extend_from_slice(&word(1760)); + bytes.extend_from_slice(&proof.proof_data.accumulator); + bytes.extend_from_slice(&proof.proof_data.proof); + bytes +} + +fn main() -> Result<()> { + let mut args = std::env::args_os().skip(1); + let action = args + .next() + .ok_or_else(|| eyre::eyre!("Expected prepare, check, prove, or verify"))?; + if action == "prepare" { + let paths: Vec = args.map(PathBuf::from).collect(); + ensure!( + paths.len() == 3, + "Expected app.pk, executable, and a new output directory" + ); + ensure!(!paths[2].exists(), "The output directory already exists"); + let app_pk: AppProvingKey = read_object_from_file(&paths[0])?; + let exe: VmExe = read_object_from_file(&paths[1])?; + let sdk = Sdk::builder() + .app_pk(app_pk) + .agg_params(AggregationSystemParams::default()) + .build()?; + let prover = sdk.prover(exe)?; + let baseline = prover.generate_baseline(); + let commit = AppExecutionCommit { + app_exe_commit: baseline.app_exe_commit.into(), + app_vm_commit: prover.app_vm_commit().into(), + }; + fs::create_dir(&paths[2])?; + write_object_to_file(paths[2].join("aggregation.pk"), sdk.agg_pk())?; + let identity = serde_json::json!({ "app_commit": commit }); + let file = fs::OpenOptions::new() + .create_new(true) + .write(true) + .open(paths[2].join("identity.json"))?; + serde_json::to_writer_pretty(file, &identity)?; + return Ok(()); + } + let config = config(&PathBuf::from( + args.next() + .ok_or_else(|| eyre::eyre!("Expected a config path"))?, + ))?; + verifier(&config)?; + if action == "check" { + ensure!(args.next().is_none(), "Unexpected arguments"); + sdk(&config)?; + return Ok(()); + } + ensure!( + action == "prove" || action == "verify", + "Expected prepare, check, prove, or verify" + ); + let paths: Vec = args.map(PathBuf::from).collect(); + ensure!( + paths.len() == 3, + "Expected input or proof, journal, and a new seal output path" + ); + ensure!(!paths[2].exists(), "The seal output already exists"); + let journal = read_limited(&paths[1], 288)?; + ensure!(journal.len() == 288, "Expected nine journal words"); + let proof: EvmProof = if action == "verify" { + serde_json::from_slice(&read_limited(&paths[0], 256 * 1024)?)? + } else { + let input = read_limited(&paths[0], 512 * 1024 * 1024 - 16)?; + let (sdk, exe) = sdk(&config)?; + eprintln!("OpenVM: proving the application"); + let app_proof = sdk + .app_prover(exe.clone())? + .prove(StdIn::from_bytes(&input))?; + drop(input); + eprintln!("OpenVM: aggregating the application proof"); + let (stark_proof, mut metadata) = sdk.agg_prover().prove_vm(app_proof)?; + let baseline = sdk.prover(exe.clone())?.generate_baseline(); + Sdk::verify_proof(sdk.agg_vk().as_ref().clone(), baseline, &stark_proof)?; + let root_proof = sdk + .evm_prover_without_halo2(exe)? + .prove_root_from_vm_stark_proof(stark_proof, &mut metadata)?; + eprintln!("OpenVM: generating the EVM proof"); + let halo2 = Sdk::builder() + .app_pk(sdk.app_pk().clone()) + .agg_pk(sdk.agg_pk()) + .root_pk(sdk.root_pk()) + .halo2_params_dir(&config.halo2_params_dir) + .halo2_pk(read_halo2_pk_from_file(&config.halo2_pk)?) + .build()?; + halo2.halo2_prover().prove_for_evm(&root_proof)? + }; + verify(&proof, &config, &journal)?; + let mut file = fs::OpenOptions::new() + .create_new(true) + .write(true) + .open(&paths[2])?; + file.write_all(&seal(&proof, &journal))?; + file.sync_all()?; + eprintln!("OpenVM: verified the proof, application identity, and all nine journal words"); + Ok(()) +} diff --git a/crates/support/program/Cargo.toml b/crates/support/program/Cargo.toml index bdff075e30..2ef42fba62 100644 --- a/crates/support/program/Cargo.toml +++ b/crates/support/program/Cargo.toml @@ -3,6 +3,12 @@ name = "e3-user-program" version = "0.1.0" edition = "2024" +[lib] +path = "../../../examples/CRISP/program/src/lib.rs" + +[features] +openvm-hashes = ["dep:openvm-sha2", "dep:openvm-keccak256", "e3-compute-provider/openvm-hashes"] + [dependencies] fhe = { workspace = true } fhe-traits = { workspace = true } @@ -10,3 +16,6 @@ e3-compute-provider = { workspace = true } e3-fhe-params = { workspace = true, features = ["abi-encoding"] } sha2 = { workspace = true } sha3 = { workspace = true } + +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } +openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } diff --git a/crates/support/scripts/build.sh b/crates/support/scripts/build.sh index 781c05a2f7..8a517cde31 100755 --- a/crates/support/scripts/build.sh +++ b/crates/support/scripts/build.sh @@ -15,7 +15,8 @@ for arg in "$@"; do done # Build with any additional arguments -docker build -t "$PKG:$GIT_SHA" "${BUILD_ARGS[@]}" . +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +docker build -t "$PKG:$GIT_SHA" -f "$ROOT/crates/support/Dockerfile" "${BUILD_ARGS[@]}" "$ROOT" # Push if --push was specified if [ "$PUSH" = true ]; then diff --git a/crates/support/scripts/container/build.sh b/crates/support/scripts/container/build.sh index 701adb0f20..f56e293822 100755 --- a/crates/support/scripts/container/build.sh +++ b/crates/support/scripts/container/build.sh @@ -1 +1,3 @@ -cargo build --locked +#!/usr/bin/env bash +set -euo pipefail +exec cargo build --locked --release --manifest-path /app/crates/support/Cargo.toml diff --git a/crates/support/scripts/container/start.sh b/crates/support/scripts/container/start.sh index 5c4fd7a64d..a7d82dbb7a 100755 --- a/crates/support/scripts/container/start.sh +++ b/crates/support/scripts/container/start.sh @@ -1,82 +1,5 @@ #!/usr/bin/env bash - -# Configuration normally arrives through Docker's environment. Flags remain supported for direct, -# backwards-compatible use and override inherited values. -POSITIONAL=() -while [[ $# -gt 0 ]]; do - case $1 in - --risc0-dev-mode) - export RISC0_DEV_MODE="$2" - shift 2 - ;; - --rpc-url) - export RPC_URL="$2" - shift 2 - ;; - --private-key) - export PRIVATE_KEY="$2" - shift 2 - ;; - --pinata-jwt) - export PINATA_JWT="$2" - shift 2 - ;; - --ipfs-gateway-url) - export IPFS_GATEWAY_URL="$2" - shift 2 - ;; - --program-url) - export PROGRAM_URL="$2" - shift 2 - ;; - --boundless-onchain) - export BOUNDLESS_ONCHAIN="$2" - shift 2 - ;; - --boundless-min-price-eth) - export BOUNDLESS_MIN_PRICE_ETH="$2" - shift 2 - ;; - --boundless-max-price-eth) - export BOUNDLESS_MAX_PRICE_ETH="$2" - shift 2 - ;; - --boundless-timeout-secs) - export BOUNDLESS_TIMEOUT_SECS="$2" - shift 2 - ;; - --boundless-lock-timeout-secs) - export BOUNDLESS_LOCK_TIMEOUT_SECS="$2" - shift 2 - ;; - --boundless-ramp-up-secs) - export BOUNDLESS_RAMP_UP_SECS="$2" - shift 2 - ;; - --boundless-lock-collateral-zkc) - export BOUNDLESS_LOCK_COLLATERAL_ZKC="$2" - shift 2 - ;; - *) - POSITIONAL+=("$1") - shift - ;; - esac -done - -set -- "${POSITIONAL[@]}" - -CARGO_INCREMENTAL=1 - -# Default to dev mode if no Boundless configuration provided -if [ -z "$RISC0_DEV_MODE" ]; then - if [ -z "$RPC_URL" ]; then - export RISC0_DEV_MODE=1 - echo "No Boundless config found, defaulting to dev mode" - fi -fi - -echo "RISC0_DEV_MODE=$RISC0_DEV_MODE" -[ -n "$RPC_URL" ] && echo "Using Boundless (RPC: $RPC_URL)" - -exec cargo run --bin e3-support-app "$@" +set -euo pipefail +: "${OPENVM_PROVER_BIN:?Set OPENVM_PROVER_BIN}" +: "${OPENVM_PROVER_CONFIG:?Set OPENVM_PROVER_CONFIG}" +exec cargo run --locked --release --manifest-path /app/crates/support/Cargo.toml -p e3-support-app -- "$@" diff --git a/crates/support/scripts/container/upload.sh b/crates/support/scripts/container/upload.sh deleted file mode 100755 index 502086dd7f..0000000000 --- a/crates/support/scripts/container/upload.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/bash -set -e - -while [[ $# -gt 0 ]]; do - case $1 in - --pinata-jwt) - export PINATA_JWT="$2" - shift 2 - ;; - --ipfs-gateway-url) - export IPFS_GATEWAY_URL="$2" - shift 2 - ;; - *) - shift - ;; - esac -done - -PROGRAM_PATH="./target/riscv-guest/methods/guests/riscv32im-risc0-zkvm-elf/release/program.bin" - -HASH_FILE="./target/.program_hash" -URL_FILE="./target/.program_url" -IPFS_GATEWAY_URL="${IPFS_GATEWAY_URL:-https://gateway.pinata.cloud}" -IPFS_GATEWAY_URL="${IPFS_GATEWAY_URL%/}" - -if [ ! -f "$PROGRAM_PATH" ]; then - echo "Error: Program not found at $PROGRAM_PATH" - echo "Run: interfold program compile" - exit 1 -fi - -if [ -z "$PINATA_JWT" ]; then - echo "Error: PINATA_JWT environment variable not set" - echo "" - echo "Please set your Pinata JWT token:" - echo " export PINATA_JWT=\"your_jwt_token\"" - echo "" - echo "Get your JWT from: https://pinata.cloud" - exit 1 -fi - -CURRENT_HASH=$(sha256sum "$PROGRAM_PATH" | awk '{print $1}') -HASH_PREFIX="${CURRENT_HASH:0:8}" -TIMESTAMP=$(date +%s) -FILE_SIZE=$(stat -f%z "$PROGRAM_PATH" 2>/dev/null || stat -c%s "$PROGRAM_PATH" 2>/dev/null || du -b "$PROGRAM_PATH" | awk '{print $1}') -FILE_SIZE_MB=$((FILE_SIZE / 1024 / 1024)) -FILE_SIZE_KB=$((FILE_SIZE / 1024)) -MODIFIED_TIME=$(stat -f%Sm "$PROGRAM_PATH" 2>/dev/null || stat -c%y "$PROGRAM_PATH" 2>/dev/null || date -r "$PROGRAM_PATH" 2>/dev/null || echo "unknown") - -FILENAME="program-${HASH_PREFIX}-${TIMESTAMP}.bin" - -echo "==========================================" -echo "Program Upload Metadata" -echo "==========================================" -echo "File path: $PROGRAM_PATH" -echo "File size: $FILE_SIZE bytes (${FILE_SIZE_MB} MB / ${FILE_SIZE_KB} KB)" -echo "SHA256 hash: $CURRENT_HASH" -echo "Modified: $MODIFIED_TIME" -echo "Upload name: $FILENAME" -echo "==========================================" -echo "" - -if [ -f "$HASH_FILE" ] && [ -f "$URL_FILE" ]; then - STORED_HASH=$(cat "$HASH_FILE") - if [ "$CURRENT_HASH" = "$STORED_HASH" ]; then - STORED_URL=$(cat "$URL_FILE") - STORED_CID="${STORED_URL##*/}" - PROGRAM_URL="$IPFS_GATEWAY_URL/ipfs/$STORED_CID" - if [ "$PROGRAM_URL" != "$STORED_URL" ]; then - echo "$PROGRAM_URL" > "$URL_FILE" - fi - echo "Program unchanged (hash matches). Existing URL:" - echo "$PROGRAM_URL" - exit 0 - else - echo "Program changed (hash differs). Uploading new version..." - echo " Old hash: $STORED_HASH" - echo " New hash: $CURRENT_HASH" - echo "" - fi -fi - -echo "Uploading program to Pinata as '$FILENAME'..." - -RESPONSE=$(curl -s -X POST "https://api.pinata.cloud/pinning/pinFileToIPFS" \ - -H "Authorization: Bearer $PINATA_JWT" \ - -F "file=@$PROGRAM_PATH;filename=$FILENAME") - -CID=$(echo "$RESPONSE" | grep -o '"IpfsHash":"[^"]*' | cut -d'"' -f4) - -if [ -z "$CID" ]; then - echo "Upload failed:" - echo "$RESPONSE" - exit 1 -fi - -# Save. Use the same gateway that Boundless will use for uploaded inputs. -PROGRAM_URL="$IPFS_GATEWAY_URL/ipfs/$CID" -echo "$CURRENT_HASH" > "$HASH_FILE" -echo "$PROGRAM_URL" > "$URL_FILE" - -echo "" -echo "✅ Upload successful!" -echo "" -echo "==========================================" -echo "Upload Confirmation" -echo "==========================================" -echo "IPFS CID: $CID" -echo "Program URL: $PROGRAM_URL" -echo "SHA256 hash: $CURRENT_HASH" -echo "File size: $FILE_SIZE bytes (${FILE_SIZE_MB} MB / ${FILE_SIZE_KB} KB)" -echo "Upload name: $FILENAME" -echo "==========================================" -echo "" -echo "The URL has been saved to .program_url" -echo "" -echo "To use this in production, add to your interfold.config.yaml:" -echo "" -echo "program:" -echo " risc0:" -echo " risc0_dev_mode: 0" -echo " boundless:" -echo " rpc_url: \"https://sepolia.infura.io/v3/YOUR_KEY\"" -echo " private_key: \"\${PRIVATE_KEY}\"" -echo " pinata_jwt: \"\${PINATA_JWT}\"" -echo " ipfs_gateway_url: \"$IPFS_GATEWAY_URL\"" -echo " program_url: \"$PROGRAM_URL\"" -echo " onchain: true" diff --git a/crates/support/scripts/dev.sh b/crates/support/scripts/dev.sh deleted file mode 100755 index 8450962baf..0000000000 --- a/crates/support/scripts/dev.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -PKG="${E3_SUPPORT_IMAGE_REPOSITORY:-ghcr.io/theinterfold/e3-support}:next" - -docker run -it \ - -v "$(pwd)/app:/app/app" \ - -v "$(pwd)/host:/app/host" \ - -v "$(pwd)/methods:/app/methods" \ - -v "$(pwd)/types:/app/types" \ - -v "$(pwd)/program:/app/program" \ - -v "$(pwd)/scripts:/app/scripts" \ - -v "$(pwd)/.interfold/generated/contracts:/app/contracts" \ - -v "$(pwd)/.interfold/generated/tests:/app/tests" \ - -v "$(pwd)/Cargo.toml:/app/Cargo.toml" \ - -v "$(pwd)/Cargo.lock:/app/Cargo.lock" \ - "$PKG" diff --git a/crates/support/types/src/lib.rs b/crates/support/types/src/lib.rs index 4f95044177..59319403ba 100644 --- a/crates/support/types/src/lib.rs +++ b/crates/support/types/src/lib.rs @@ -79,6 +79,28 @@ pub struct ComputeJournal { } impl ComputeJournal { + /// Encode the nine journal fields as Solidity ABI words. + pub fn abi_bytes(&self) -> std::result::Result, String> { + let fields = [ + &self.chain_id, + &self.verifying_contract, + &self.e3_id, + &self.encryption_scheme_id, + &self.committee_public_key_hash, + &self.ciphertext_hash, + &self.ciphertext_commitment, + &self.params_hash, + &self.merkle_root, + ]; + if fields.iter().any(|field| field.len() != 32) { + return Err("Each journal field must contain 32 bytes".into()); + } + Ok(fields + .into_iter() + .flat_map(|field| field.iter().copied()) + .collect()) + } + pub fn new(domain: ComputeDomain, result: ComputeResult) -> std::result::Result { for (name, value) in [ ("ciphertext hash", &result.ciphertext_hash), diff --git a/crates/zk-helpers/src/circuits/commitments.rs b/crates/zk-helpers/src/circuits/commitments.rs index 5a28c1ed75..c59da61749 100644 --- a/crates/zk-helpers/src/circuits/commitments.rs +++ b/crates/zk-helpers/src/circuits/commitments.rs @@ -10,7 +10,7 @@ //! (polynomials, public keys, secret keys, shares, etc.) using the SAFE sponge hash function. //! All functions match the corresponding Noir circuit implementations exactly. -use crate::packing::flatten; +use crate::packing::{flatten, pack_centered_rns_row}; use crate::utils::compute_safe; use ark_bn254::Fr as Field; use ark_ff::BigInteger; @@ -18,6 +18,7 @@ use ark_ff::PrimeField; use e3_fhe_params::{build_pair_for_preset, BfvPreset}; use e3_polynomial::{CrtPolynomial, Polynomial}; use fhe::bfv::PublicKey; +use fhe_math::rq::{Poly, PowerBasis}; use fhe_traits::DeserializeParametrized; use num_bigint::BigInt; use std::slice::from_ref; @@ -440,10 +441,35 @@ pub fn compute_ciphertext_commitment( bit_ct: u32, ) -> BigInt { let payload0 = flatten(Vec::new(), &ct0.limbs, bit_ct); + let payload1 = flatten(Vec::new(), &ct1.limbs, bit_ct); + ciphertext_commitment_from_packed(payload0, payload1) +} + +/// Computes the same SAFE commitment directly from canonical power-basis rows. +/// Returns `None` when the caller must use the general polynomial path. +pub fn compute_ciphertext_commitment_from_power_basis( + ct0: &Poly, + ct1: &Poly, + moduli: &[u64], + bit_ct: u32, +) -> Option { + let pack = |component: &Poly| { + if component.coefficients().nrows() != moduli.len() { + return None; + } + let mut payload = Vec::new(); + for (row, modulus) in component.coefficients().outer_iter().zip(moduli.iter()) { + payload.extend(pack_centered_rns_row(row.as_slice()?, *modulus, bit_ct)?); + } + Some(payload) + }; + Some(ciphertext_commitment_from_packed(pack(ct0)?, pack(ct1)?)) +} + +fn ciphertext_commitment_from_packed(payload0: Vec, payload1: Vec) -> BigInt { let io = [0x80000000 | payload0.len() as u32, 1]; let commit_ct0 = compute_commitments(payload0, DS_CIPHERTEXT, io)[0]; - let payload1 = flatten(Vec::new(), &ct1.limbs, bit_ct); let commit_ct1 = compute_commitments(payload1, DS_CIPHERTEXT, io)[0]; let inputs = vec![commit_ct0, commit_ct1]; diff --git a/crates/zk-helpers/src/packing.rs b/crates/zk-helpers/src/packing.rs index 74b02c0562..3d8d43bacd 100644 --- a/crates/zk-helpers/src/packing.rs +++ b/crates/zk-helpers/src/packing.rs @@ -10,10 +10,10 @@ //! using a nibble-aligned layout, matching the Noir implementation exactly. use ark_bn254::Fr as Field; -use ark_ff::PrimeField; +use ark_ff::{BigInt as FieldInteger, BigInteger, PrimeField}; use e3_polynomial::Polynomial; use num_bigint::BigInt; -use num_traits::Zero; +use num_traits::{ToPrimitive, Zero}; /// Compute hex-aligned packing parameters for a given `BIT`. /// Matches the Noir `packing_layout` function exactly. @@ -53,6 +53,48 @@ fn packing_layout(bit: u32) -> (u32, u32) { /// The number of field elements is `ceil(poly.coefficients().len() / group)` where `group` is /// determined by the packing layout. fn packer(polynomial: &Polynomial, bit: u32) -> Vec { + packer_fixed_width(polynomial, bit).unwrap_or_else(|| packer_bigint(polynomial, bit)) +} + +/// Uses four machine words when each shifted coefficient fits its allocated digit. +/// Other values use the original arbitrary-precision path. +fn packer_fixed_width(polynomial: &Polynomial, bit: u32) -> Option> { + let (nibble_bits, group) = packing_layout(bit); + if nibble_bits > 120 { + return None; + } + let digit_bits = nibble_bits + 4; + let base = 1i128 << nibble_bits; + let radix = 1u128 << digit_bits; + let values = polynomial.coefficients(); + let mut output = Vec::with_capacity(values.len().div_ceil(group as usize)); + for chunk in values.chunks(group as usize) { + let mut accumulator = FieldInteger::<4>::from(0u64); + for index in 0..group as usize { + let value = match chunk.get(index) { + Some(value) => value.to_i128()?, + None => 0, + }; + let digit = u128::try_from(value.checked_add(base)?).ok()?; + if digit >= radix { + return None; + } + accumulator <<= digit_bits; + let carry = accumulator.add_with_carry(&FieldInteger([ + digit as u64, + (digit >> 64) as u64, + 0, + 0, + ])); + debug_assert!(!carry); + } + // The nibble-aligned layout uses at most 252 bits, below the field modulus. + output.push(Field::from_bigint(accumulator)?); + } + Some(output) +} + +fn packer_bigint(polynomial: &Polynomial, bit: u32) -> Vec { let values = polynomial.coefficients(); let (nibble_bits, group) = packing_layout(bit); @@ -118,10 +160,143 @@ pub fn flatten(mut inputs: Vec, polynomials: &[Polynomial], bit: u32) -> inputs } +/// Reverses, centers, and packs one canonical RNS row without per-coefficient allocations. +/// Returns `None` if the row cannot use the fixed-width path. +pub fn pack_centered_rns_row(coefficients: &[u64], modulus: u64, bit: u32) -> Option> { + let (nibble_bits, group) = packing_layout(bit); + if modulus == 0 || nibble_bits > 120 || coefficients.iter().any(|value| *value >= modulus) { + return None; + } + let base = 1i128 << nibble_bits; + let digit_bits = nibble_bits + 4; + let radix = 1u128 << digit_bits; + let group = group as usize; + let mut values = coefficients.iter().rev(); + let mut output = Vec::with_capacity(coefficients.len().div_ceil(group)); + for _ in 0..coefficients.len().div_ceil(group) { + let mut accumulator = FieldInteger::<4>::from(0u64); + for _ in 0..group { + let value = values.next().copied().unwrap_or(0); + let negative = if modulus % 2 == 0 { + value >= modulus / 2 + } else { + value > modulus / 2 + }; + let centered = i128::from(value) - if negative { i128::from(modulus) } else { 0 }; + let digit = u128::try_from(centered.checked_add(base)?).ok()?; + if digit >= radix { + return None; + } + accumulator <<= digit_bits; + if accumulator.add_with_carry(&FieldInteger([digit as u64, (digit >> 64) as u64, 0, 0])) + { + return None; + } + } + output.push(Field::from_bigint(accumulator)?); + } + Some(output) +} + #[cfg(test)] mod tests { use super::*; + #[test] + fn direct_rns_packing_matches_reverse_center_and_bigint_packing() { + for modulus in [ + 2u64, + 3, + 16, + 17, + 65537, + (1 << 51) - 1, + (1 << 62) - 57, + u64::MAX, + ] { + let bit = 64 - (modulus / 2).leading_zeros(); + for length in [0, 1, 3, 4, 7, 16, 31, 512] { + let edges = [0, 1, modulus / 2, modulus - 1]; + let coefficients: Vec<_> = edges.into_iter().cycle().take(length).collect(); + let mut reference = Polynomial::from_u64_vector(coefficients.clone()); + reference.reverse(); + reference.center(&BigInt::from(modulus)); + assert_eq!( + pack_centered_rns_row(&coefficients, modulus, bit).unwrap(), + packer_bigint(&reference, bit) + ); + } + } + assert!(pack_centered_rns_row(&[17], 17, 5).is_none()); + assert!(pack_centered_rns_row(&[0], 0, 5).is_none()); + } + + #[test] + fn fixed_width_packing_matches_bigint_at_boundaries() { + for bit in [0, 1, 4, 5, 8, 31, 32, 51, 53, 60, 64, 100, 120] { + let (nibble_bits, group) = packing_layout(bit); + let base = BigInt::from(1) << nibble_bits; + let edge = vec![ + -&base, + -&base + 1, + BigInt::from(-1), + BigInt::zero(), + &base - 1, + base, + ]; + for length in [ + 0, + 1, + group as usize - 1, + group as usize, + group as usize + 1, + 100, + ] { + let polynomial = + Polynomial::new(edge.iter().cycle().take(length).cloned().collect()); + assert_eq!( + packer_fixed_width(&polynomial, bit).unwrap(), + packer_bigint(&polynomial, bit) + ); + } + } + } + + #[test] + fn fixed_width_packing_matches_bigint_for_deterministic_samples() { + let mut state = 7u64; + for bit in 1..=64 { + let values = (0..131) + .map(|_| { + state ^= state << 13; + state ^= state >> 7; + state ^= state << 17; + let magnitude = u128::from(state) & ((1u128 << bit) - 1); + let value = BigInt::from(magnitude); + if state & 1 == 0 { + value + } else { + -value + } + }) + .collect(); + let polynomial = Polynomial::new(values); + assert_eq!( + packer_fixed_width(&polynomial, bit).unwrap(), + packer_bigint(&polynomial, bit) + ); + } + } + + #[test] + fn packing_retains_bigint_fallback() { + for (bit, value) in [(8, BigInt::from(1) << 40), (200, BigInt::from(1) << 199)] { + let polynomial = Polynomial::new(vec![value]); + assert!(packer_fixed_width(&polynomial, bit).is_none()); + assert_eq!(packer(&polynomial, bit), packer_bigint(&polynomial, bit)); + } + } + #[test] fn test_packing_layout() { // Test nibble alignment diff --git a/eslint.config.mjs b/eslint.config.mjs index c9fdff6a3f..ca5f4e319f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,9 +3,9 @@ import config from '@interfold/config/eslint.config.js' export default defineConfig([ globalIgnores([ - // Github submodules. - 'examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum', - 'templates/default/lib/risc0-ethereum', + // External Solidity libraries, including copies retained by older checkouts. + 'examples/CRISP/packages/crisp-contracts/lib/**', + 'templates/default/lib/**', // Build and cache directories. '**/node_modules/**', '**/dist/**', diff --git a/examples/CRISP/.gitignore b/examples/CRISP/.gitignore index ac9471309c..a173b28785 100644 --- a/examples/CRISP/.gitignore +++ b/examples/CRISP/.gitignore @@ -49,8 +49,6 @@ playwright-report/ .interfold/caches/ .interfold/ready .interfold/noir/ -# ZEN2-10: the guest image id is generated by the pinned Docker build. The canonical copy is -# `crates/support/contracts/ImageID.sol`, which the deployment script and the activation -# validator read. A tracked copy here has no consumer and goes stale silently. +# Deployment-local generated files are not program source. .interfold/generated/ cache_hardhat/ diff --git a/examples/CRISP/Cargo.lock b/examples/CRISP/Cargo.lock index d7fd4983f1..78cd1ee785 100644 --- a/examples/CRISP/Cargo.lock +++ b/examples/CRISP/Cargo.lock @@ -2934,6 +2934,7 @@ dependencies = [ "light-poseidon 0.2.0", "num-bigint 0.4.6", "num-traits", + "openvm-keccak256", "serde", "sha2 0.10.9", "sha3", @@ -3053,7 +3054,6 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "risc0-bigint2", "sha3", "taceo-poseidon2", ] @@ -3083,6 +3083,7 @@ dependencies = [ name = "e3-user-program" version = "0.1.0" dependencies = [ + "anyhow", "e3-bfv-client", "e3-compute-provider", "e3-fhe-params", @@ -3090,6 +3091,7 @@ dependencies = [ "fhe-traits", "hex", "num-bigint 0.5.1", + "openvm-sha2", "rand 0.9.5", "serde_json", "sha2 0.10.9", @@ -4289,12 +4291,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "include_bytes_aligned" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" - [[package]] name = "indenter" version = "0.3.4" @@ -5221,6 +5217,69 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openvm-keccak256" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-keccak256-guest", + "spin 0.10.1", + "tiny-keccak", +] + +[[package]] +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros 0.26.4", +] + +[[package]] +name = "openvm-sha2" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-sha2-guest", + "sha2 0.10.9", +] + +[[package]] +name = "openvm-sha2-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + [[package]] name = "ordered-multimap" version = "0.6.0" @@ -6092,16 +6151,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "risc0-bigint2" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87f5f7494a2242cead2750b7ce2b8522c1be83dee268479f1c12ed521eaf595" -dependencies = [ - "include_bytes_aligned", - "stability", -] - [[package]] name = "rlp" version = "0.5.2" @@ -7069,6 +7118,12 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" + [[package]] name = "spki" version = "0.7.3" @@ -7079,16 +7134,6 @@ dependencies = [ "der", ] -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.117", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -7123,7 +7168,20 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ - "strum_macros", + "strum_macros 0.27.2", +] + +[[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.117", ] [[package]] @@ -8079,7 +8137,7 @@ dependencies = [ "num-derive", "num-traits", "smallvec", - "spin", + "spin 0.9.9", "wasmi_collections", "wasmi_core", "wasmparser-nostd", diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index 5b75f3574f..2a05246c58 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -22,7 +22,7 @@ root structure. CRISP/ ├── client/ # React frontend application (Vite + @crisp-e3/sdk) ├── server/ # Rust coordination server & CLI -├── program/ # FHE program for encrypted computation + RISC Zero verification +├── program/ # FHE policy proved with OpenVM ├── packages/ │ ├── crisp-contracts/ # CRISP program contract + Hardhat deployment scripts │ └── crisp-sdk/ # TypeScript helpers to generate a ZK proof @@ -54,20 +54,22 @@ Before getting started, ensure you have installed: - `nargo`: `noirup -v v1.0.0-beta.26` (`NOIR_TOOLCHAIN` in `.github/workflows/ci.yml`) - `bb`: version and per-platform checksums live in `crates/zk-prover/versions.json` -[RiscZero](https://dev.risczero.com/api/zkvm/install) is **not** required for local development. -`scripts/dev_program.sh` starts the program server with `--dev true`, so `pnpm dev:up` runs without -a proving backend no matter what `program.dev` says in `interfold.config.yaml`. Real proving runs -inside a container image that already ships RiscZero, so what that path needs locally is **Docker**, -not a RiscZero install. +The program server uses OpenVM by default. Before startup, build the guest and worker, prepare the +keys, and configure `program.openvm` in `interfold.config.yaml`. Follow +[`crates/support/openvm/README.md`](../../crates/support/openvm/README.md). The CUDA worker needs a +compatible Linux GPU environment; the native HTTP service has no CUDA dependency. + +Deployment also requires `OPENVM_APP_EXE_COMMIT`, `OPENVM_APP_VM_COMMIT`, and either +`OPENVM_VERIFIER_ARTIFACT` with `OPENVM_VERIFIER_SHA256`, or `OPENVM_HALO2_VERIFIER` with +`OPENVM_HALO2_RUNTIME_CODE_HASH`. These values must describe the worker's actual artifacts. The +CRISP deployment never selects a mock compute verifier. ## Quick Start The simplest way to run CRISP is: ```bash -# From the repository root — the CRISP contracts depend on the risc0-ethereum submodule -git submodule update --init --recursive - +# From the repository root cd examples/CRISP # Optional: choose local profile (copied to crisp.dev.env on first setup) @@ -81,10 +83,6 @@ pnpm dev:setup pnpm dev:up ``` -> **_Note:_** Without the submodule step, `pnpm dev:setup` fails while compiling contracts with -> `HHE902 ... lib/risc0-ethereum/contracts/src/groth16/RiscZeroGroth16Verifier.sol doesn't exist`. -> CI does not hit this because its checkout uses `submodules: recursive`. - The program server accepts caller-supplied HTTP(S) callback URLs. It is a development-only test service, does not authenticate callers or allowlist callback destinations, and must stay isolated from production and untrusted networks. @@ -149,58 +147,20 @@ program: dev: true # Uses fake zkVM proofs (fast for development) ``` -### Boundless Configuration - -For production-grade zero-knowledge proofs with [Boundless](https://docs.boundless.network/), update -`interfold.config.yaml`: - -```yaml -program: - dev: false # Disable dev mode to use real proofs - risc0: - risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode - boundless: - rpc_url: 'https://sepolia.infura.io/v3/YOUR_KEY' # RPC endpoint - private_key: 'YOUR_PRIVATE_KEY' # Wallet with funds for proving - pinata_jwt: 'YOUR_PINATA_JWT' # Required for uploading programs to IPFS - # The gateway must allow full, unauthenticated downloads by Boundless provers. - ipfs_gateway_url: 'https://your-gateway.mypinata.cloud' - program_url: 'https://your-gateway.mypinata.cloud/ipfs/YOUR_CID' # Pre-uploaded program URL - onchain: true # true = onchain requests, false = offchain -``` - -> **_Note:_** For production proving with Boundless, you need: -> -> - An RPC endpoint (e.g., Infura, Alchemy) with funds -> - A private key with sufficient ETH/tokens for proof generation -> - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) -> - Pre-uploaded program URL to avoid uploading the ~40MB program at runtime - -#### Uploading Your Program to IPFS - -When you make changes to the guest program in `program/`, you need to upload it to IPFS to get a -program URL: - -1. First, configure your Pinata JWT in `interfold.config.yaml` (as shown above) - -2. Build and upload your program: - - ```bash - # This compiles the guest program and uploads it to IPFS via Pinata - interfold program upload - ``` +### OpenVM configuration -3. The command will output an IPFS hash like `QmXxx...`. Update your `interfold.config.yaml` with - the full URL: +The real-proof compute service now uses OpenVM. Follow the +[OpenVM build and migration guide](../../crates/support/openvm/README.md) to build the guest and +worker, derive the application identity, and configure proving artifacts. - ```yaml - ipfs_gateway_url: 'https://your-gateway.mypinata.cloud' - program_url: 'https://your-gateway.mypinata.cloud/ipfs/QmXxx...' - ``` +Set `program.dev: false` and supply deployment-local `program.openvm.repository`, +`program.openvm.prover_bin`, and `program.openvm.prover_config` paths. Do not put account keys, +proving artifacts, or machine-specific values in the shared configuration. -> **_Important:_** Every time you modify the guest program code in `program/`, you must rebuild and -> re-upload it to IPFS, then update the `program_url` in your configuration. This ensures Boundless -> uses your latest program version. +A new OpenVM deployment requires matching receipt and ciphertext-duty verifiers. Existing RISC Zero +deployments do not become compatible by changing the service configuration. Drain active rounds and +use a separate reviewed migration before changing a live verifier route. The old Boundless upload +and auction settings are not used by this backend. ### Encrypted-object data availability @@ -297,7 +257,7 @@ service limits the total bytes held by unfinished jobs, which bounds abandoned s deleting data that Ethereum already accepted. After Avail and Ethereum accept an object, the service removes its staging copy because Avail is then the recovery source. -The aggregate ciphertext follows the Avail and VectorX path after its RISC Zero proof is ready. +The aggregate ciphertext follows the Avail and VectorX path after its OpenVM proof is ready. Each accepted Ethereum reference contains `keccak256(exact bytes)`. The CRISP server and ciphernodes re-hash retrieved bytes before they use them. An App ID helps indexing, but it is not a security diff --git a/examples/CRISP/eslint.config.js b/examples/CRISP/eslint.config.js index 10cfa75a3c..6c453f4ce1 100644 --- a/examples/CRISP/eslint.config.js +++ b/examples/CRISP/eslint.config.js @@ -9,8 +9,8 @@ import config from '@interfold/config/eslint.config.js' export default defineConfig([ globalIgnores([ - // Github submodules. - 'packages/crisp-contracts/lib/risc0-ethereum', + // External Solidity libraries, including copies retained by older checkouts. + 'packages/crisp-contracts/lib/**', // Build and cache directories. '**/node_modules/**', '**/dist/**', diff --git a/examples/CRISP/interfold.config.yaml b/examples/CRISP/interfold.config.yaml index ba5c0f07c8..4e8798a0cd 100644 --- a/examples/CRISP/interfold.config.yaml +++ b/examples/CRISP/interfold.config.yaml @@ -84,23 +84,9 @@ chains: address: "0xA7f0A637Af62fA4E0b46E397D1b85E9b4807f019" deploy_block: 11856142 program: - dev: true - # risc0: - # risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode (fake proofs) - # boundless: - # rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" - # private_key: "PRIVATE_KEY" # Use env vars for secrets - # pinata_jwt: "PINATA_JWT" # For uploading programs - # ipfs_gateway_url: "https://gateway.pinata.cloud" # Public full-download gateway for programs and inputs - # program_url: "https://gateway.pinata.cloud/ipfs/QmdSmZPD9ArQYY754pbvji9bfiqAmG1rmoLci1fN9vMPdF" # Guest for ImageID.sol - # onchain: true # true = onchain requests, false = offchain - # Optional — custom auction parameters (defaults shown): - # min_price_eth: 0.00005 - # max_price_eth: 0.004 - # timeout_secs: 28800 - # lock_timeout_secs: 14400 - # ramp_up_secs: 7200 - # lock_collateral_zkc: 100.0 + dev: false + # Real proofs use program.openvm. Configure repository, prover_bin, + # and prover_config as deployment-local absolute paths. See crates/support/openvm/README.md. # The scheduler defaults to 2 concurrent jobs and reserves 2 logical CPUs for Actix / libp2p. # It reduces concurrency when the host or cgroup memory limit is too small. # Example override on a dedicated 64 GB host: diff --git a/examples/CRISP/packages/crisp-contracts/README.md b/examples/CRISP/packages/crisp-contracts/README.md index 67de6f0df1..7f990ad0b1 100644 --- a/examples/CRISP/packages/crisp-contracts/README.md +++ b/examples/CRISP/packages/crisp-contracts/README.md @@ -31,7 +31,7 @@ Local deploy is driven by **`../../crisp.dev.env`** (see ### CRISP-only deploy (Interfold already deployed) ```bash -pnpm deploy:contracts # production RISC0 verifier +pnpm deploy:contracts # configured OpenVM verifier pnpm deploy:contracts:full # also deploy Interfold stack (no ZK unless ENABLE_ZK_VERIFICATION=true) ``` @@ -45,8 +45,8 @@ It exposes three main functions: (`Interfold.request`). - `verify` - that is called when the ciphertext output is published on Interfold (`Interfold.publishCiphertextOutput`). This function ensures that the ciphertext output is valid. - CRISP uses Risc0 as the compute provider for running the FHE program, thus the proof will be a - Risc0 proof. + CRISP uses OpenVM to prove the FHE program. The receipt adapter checks the application identity, + journal digest, and Halo2 proof. CRISP also checks its stored parameter hash and input root. - `publishInput` - accepts the compact proof commitment for an input. A voter or relay calls it after the CRISP availability service has durably stored the ciphertext and signed the input ID with a 10-minute expiry. The function checks the stage, commitment cutoff, signed expiry, voter diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol index 6e3566f50e..5d9d836c74 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol @@ -5,13 +5,13 @@ // or FITNESS FOR A PARTICULAR PURPOSE. pragma solidity >=0.8.27; -import { IRiscZeroVerifier } from "risc0/IRiscZeroVerifier.sol"; +import { IOpenVmReceiptVerifier } from "@interfold/contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IE3Program } from "@interfold/contracts/contracts/interfaces/IE3Program.sol"; import { IInterfold } from "@interfold/contracts/contracts/interfaces/IInterfold.sol"; import { ICiphernodeRegistry } from "@interfold/contracts/contracts/interfaces/ICiphernodeRegistry.sol"; import { E3 } from "@interfold/contracts/contracts/interfaces/IE3.sol"; -import { Risc0ComputeProof } from "@interfold/contracts/contracts/lib/Risc0ComputeProof.sol"; +import { OpenVmComputeProof } from "@interfold/contracts/contracts/lib/OpenVmComputeProof.sol"; import { LazyIMTData, InternalLazyIMT } from "@zk-kit/lazy-imt.sol/InternalLazyIMT.sol"; import { SNARK_SCALAR_FIELD } from "@zk-kit/lazy-imt.sol/Constants.sol"; import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; @@ -151,7 +151,7 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl uint8 constant MAX_DERIVABLE_DECIMALS = 78; // State variables IInterfold public interfold; - IRiscZeroVerifier public risc0Verifier; + IOpenVmReceiptVerifier public openVmVerifier; bytes32 public imageId; /// @notice Verifies ballots for the census modes that prove membership of a Merkle tree. IHonkVerifier private immutable honkVerifier; @@ -191,7 +191,7 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl error InterfoldAlreadyBound(); error InterfoldNotContract(); error ProgramNotRegistered(); - error Risc0VerifierAddressZero(); + error OpenVmVerifierAddressZero(); error InvalidHonkVerifier(); error EmptyInputData(); error InvalidNoirProof(); @@ -287,12 +287,12 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl /// @notice Initialize the contract without an Interfold controller. /// @dev The owner binds the controller after Interfold registers this program. /// @param _initialOwner The account that can configure and bind this program. - /// @param _risc0Verifier The RISC Zero verifier address + /// @param _openVmVerifier The OpenVM receipt verifier address /// @param _honkVerifier The honk verifier address /// @param _imageId The image ID for the guest program constructor( address _initialOwner, - IRiscZeroVerifier _risc0Verifier, + IOpenVmReceiptVerifier _openVmVerifier, IHonkVerifier _honkVerifier, IHonkVerifier _onchainHonkVerifier, IDataAvailabilityVerifier _dataAvailabilityVerifier, @@ -300,12 +300,12 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl address _inputAvailabilitySigner, bytes32 _imageId ) Ownable(_initialOwner) EIP712("CRISP", "1") { - if (address(_risc0Verifier) == address(0)) revert Risc0VerifierAddressZero(); + if (address(_openVmVerifier) == address(0)) revert OpenVmVerifierAddressZero(); if (address(_honkVerifier) == address(0)) revert InvalidHonkVerifier(); if (address(_onchainHonkVerifier) == address(0)) revert InvalidHonkVerifier(); if (address(_dataAvailabilityVerifier).code.length == 0) revert InvalidDataAvailabilityVerifier(); - risc0Verifier = _risc0Verifier; + openVmVerifier = _openVmVerifier; honkVerifier = _honkVerifier; onchainHonkVerifier = _onchainHonkVerifier; dataAvailabilityVerifier = _dataAvailabilityVerifier; @@ -365,12 +365,12 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl imageId = _imageId; } - /// @notice Set the RISC Zero verifier. + /// @notice Set the OpenVM receipt verifier. /// @dev Carries the same in-flight risk as `setImageId`. Change it only between rounds. - /// @param _risc0Verifier The new RISC Zero verifier address - function setRisc0Verifier(IRiscZeroVerifier _risc0Verifier) external onlyOwner { - if (address(_risc0Verifier) == address(0)) revert Risc0VerifierAddressZero(); - risc0Verifier = _risc0Verifier; + /// @param _openVmVerifier The new OpenVM receipt verifier address + function setOpenVmVerifier(IOpenVmReceiptVerifier _openVmVerifier) external onlyOwner { + if (address(_openVmVerifier) == address(0)) revert OpenVmVerifierAddressZero(); + openVmVerifier = _openVmVerifier; } /// @notice Get the params hash for an E3 program @@ -1002,10 +1002,10 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl E3 memory e3 = interfold.getE3(e3Id); bytes32 paramsHash = getParamsHash(e3Id); bytes32 inputRoot = bytes32(e3Data[e3Id].votes._root()); - Risc0ComputeProof.Proof memory computeProof = Risc0ComputeProof.decode(proof); + OpenVmComputeProof.Proof memory computeProof = OpenVmComputeProof.decode(proof); if (computeProof.paramsHash != paramsHash || computeProof.inputRoot != inputRoot) revert InvalidComputeContext(); - bytes memory journal = Risc0ComputeProof.journal( + bytes memory journal = OpenVmComputeProof.journal( bytes32(block.chainid), bytes32(uint256(uint160(address(interfold)))), bytes32(e3Id), @@ -1017,7 +1017,7 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl inputRoot ); - risc0Verifier.verify(computeProof.seal, imageId, sha256(journal)); + openVmVerifier.verify(computeProof.seal, imageId, sha256(journal)); return true; } diff --git a/examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockRISC0Verifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockComputeReceiptVerifier.sol similarity index 77% rename from examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockRISC0Verifier.sol rename to examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockComputeReceiptVerifier.sol index 2b94a032e8..a01514a826 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockRISC0Verifier.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockComputeReceiptVerifier.sol @@ -5,9 +5,9 @@ // or FITNESS FOR A PARTICULAR PURPOSE. pragma solidity ^0.8.27; -import { IRiscZeroVerifier, Receipt } from "risc0/IRiscZeroVerifier.sol"; +import { IOpenVmReceiptVerifier } from "@interfold/contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol"; -contract MockRISC0Verifier is IRiscZeroVerifier { +contract MockComputeReceiptVerifier is IOpenVmReceiptVerifier { bytes32 public expectedJournalDigest; error UnexpectedJournalDigest(bytes32 actual, bytes32 expected); @@ -21,6 +21,4 @@ contract MockRISC0Verifier is IRiscZeroVerifier { revert UnexpectedJournalDigest(journalDigest, expectedJournalDigest); } } - - function verifyIntegrity(Receipt calldata receipt) external view override {} } diff --git a/examples/CRISP/packages/crisp-contracts/contracts/Mocks/RiscZeroGroth16Verifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/Mocks/RiscZeroGroth16Verifier.sol deleted file mode 100644 index 8403aac742..0000000000 --- a/examples/CRISP/packages/crisp-contracts/contracts/Mocks/RiscZeroGroth16Verifier.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -pragma solidity >=0.8.27; - -import { RiscZeroGroth16Verifier as RiscZero } from "risc0/groth16/RiscZeroGroth16Verifier.sol"; -import { ControlID } from "risc0/groth16/ControlID.sol"; - -contract RiscZeroGroth16Verifier is RiscZero { - constructor() RiscZero(ControlID.CONTROL_ROOT, ControlID.BN254_CONTROL_ID) {} -} diff --git a/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmCallVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmCallVerifier.sol new file mode 100644 index 0000000000..0fcd2d9917 --- /dev/null +++ b/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmCallVerifier.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +pragma solidity 0.8.28; + +/// @notice Test-only call oracle. This contract does not verify a cryptographic proof. +contract MockOpenVmCallVerifier { + bytes32 private expectedCall; + error UnexpectedOpenVmCall(); + + function setExpectedCall(bytes calldata publicValues, bytes calldata proofData, bytes32 exeCommit, bytes32 vmCommit) external { + expectedCall = keccak256(abi.encode(publicValues, proofData, exeCommit, vmCommit)); + } + + function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 exeCommit, bytes32 vmCommit) external view { + if (keccak256(abi.encode(publicValues, proofData, exeCommit, vmCommit)) != expectedCall) revert UnexpectedOpenVmCall(); + } +} diff --git a/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts b/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts index 18745f9e43..3a75963551 100644 --- a/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts +++ b/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts @@ -119,7 +119,7 @@ async function main() { const interfold = requireAddress(protocolDeployment.interfold, 'Interfold') const crispProgram = requireAddress(chainDeployments.CRISPProgram?.address, 'CRISPProgram') - const ciphertextVerifier = requireAddress(chainDeployments.Risc0BfvCiphertextVerifier?.address, 'Risc0BfvCiphertextVerifier') + const ciphertextVerifier = requireAddress(chainDeployments.OpenVmBfvCiphertextVerifier?.address, 'OpenVmBfvCiphertextVerifier') const adminPlugin = requireAddress(protocolConfig.governance.adminPlugin, 'Aragon Admin plugin') const proposerSafe = requireAddress(protocolConfig.governance.proposerSafe, 'Governance proposer Safe') const encryptionSchemeId = ethers.keccak256(ethers.toUtf8Bytes('fhe.rs:BFV')) @@ -188,7 +188,7 @@ async function main() { chain: ${chain} Interfold: ${interfold} CRISPProgram: ${crispProgram} - Risc0Bfv verifier: ${ciphertextVerifier} + OpenVM BFV verifier: ${ciphertextVerifier} encryptionSchemeId: ${encryptionSchemeId} raw DAO actions: ${rawActionsPath} Safe Builder wrapper: ${safeBuilderPath}`) diff --git a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts index 24e6dffd61..330437576a 100644 --- a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts +++ b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts @@ -7,28 +7,18 @@ import { AVAIL_FINALIZATION_WINDOW_SECONDS, AVAIL_VECTORX, + deployOpenVmReceiptVerifier, getDeploymentChain, readDeploymentArgs, storeDeploymentArgs, } from '@interfold/contracts/scripts' import { Interfold__factory as InterfoldFactory } from '@interfold/contracts/types' -import { readFileSync } from 'fs' import hre from 'hardhat' import { CRISPProgram__factory as CRISPProgramFactory } from '../types' import { verifierNames } from '../scripts/verifiers' -// The production guest lives in crates/support. Read the Image ID generated from that exact -// guest instead of the example project's cached copy, which can lag behind a guest change. -const imageIdContent = readFileSync(new URL('../../../../../crates/support/contracts/ImageID.sol', import.meta.url), 'utf-8') -const match = imageIdContent.match(/bytes32 public constant PROGRAM_ID = bytes32\((0x[a-fA-F0-9]+)\)/) -const IMAGE_ID = match ? match[1] : null - -if (!IMAGE_ID) { - throw new Error('IMAGE_ID not found') -} - export interface CRISPDeploymentResult { governanceComplete: boolean } @@ -85,10 +75,12 @@ export const deployCRISPContracts = async (): Promise => })() const verifier = await deployVerifier(useMocks, ethers) + const receiptVerifier = await ethers.getContractAt('OpenVmReceiptVerifier', verifier) + const IMAGE_ID = await receiptVerifier.imageId() const encryptionSchemeId = ethers.keccak256(ethers.toUtf8Bytes('fhe.rs:BFV')) - const ciphertextVerifier = await ethers.deployContract('Risc0BfvCiphertextVerifier', [verifier, IMAGE_ID]) + const ciphertextVerifier = await ethers.deployContract('OpenVmBfvCiphertextVerifier', [verifier, IMAGE_ID]) await ciphertextVerifier.waitForDeployment() const ciphertextVerifierAddress = await ciphertextVerifier.getAddress() storeDeploymentArgs( @@ -97,7 +89,7 @@ export const deployCRISPContracts = async (): Promise => blockNumber: await ethers.provider.getBlockNumber(), constructorArgs: { verifier, imageId: IMAGE_ID }, }, - 'Risc0BfvCiphertextVerifier', + 'OpenVmBfvCiphertextVerifier', chain, ) let poseidonT3Address = readDeploymentArgs('PoseidonT3', chain)?.address @@ -308,8 +300,8 @@ export const deployCRISPContracts = async (): Promise => Deployments: ---------------------------------------------------------------------- Interfold: ${interfoldAddress ?? '(bind during protocol governance wiring)'} - Risc0Verifier: ${verifier} - Risc0BfvCiphertextVerifier: ${ciphertextVerifierAddress} + OpenVmVerifier: ${verifier} + OpenVmBfvCiphertextVerifier: ${ciphertextVerifierAddress} HonkVerifier: ${honkVerifierAddress} OnchainHonkVerifier: ${onchainHonkVerifierAddress} DataAvailabilityVerifier: ${dataAvailabilityVerifierAddress} @@ -321,54 +313,25 @@ export const deployCRISPContracts = async (): Promise => return { governanceComplete } } -/** - * Deploys the verifier contract - * @param useMockVerifier - whether to use a mock verifier - * @returns The address of the verifier - */ -export const deployVerifier = async (useMockVerifier: boolean, connectedEthers?: any): Promise => { +/** Deploy the receipt binding for an explicitly configured OpenVM Halo2 verifier. */ +export const deployVerifier = async (_useMockVerifier: boolean, connectedEthers?: any): Promise => { const ethers = connectedEthers ?? (await hre.network.connect()).ethers const chain = getDeploymentChain(hre) - - if (!useMockVerifier) { - const existingVerifier = readDeploymentArgs('RiscZeroGroth16Verifier', chain) - if (existingVerifier?.address && (await ethers.provider.getCode(existingVerifier.address)) !== '0x') { - console.log('RiscZeroGroth16Verifier already deployed at:', existingVerifier.address) - return existingVerifier.address - } - const verifierFactory = await ethers.getContractFactory('RiscZeroGroth16Verifier') - const verifier = await verifierFactory.deploy() - await verifier.waitForDeployment() - const address = await verifier.getAddress() - - storeDeploymentArgs( - { - address, - blockNumber: await ethers.provider.getBlockNumber(), - }, - 'RiscZeroGroth16Verifier', - chain, - ) - return address - } - // Check if mock verifier already deployed - const existingMockVerifier = readDeploymentArgs('MockRISC0Verifier', chain) - if (existingMockVerifier?.address && (await ethers.provider.getCode(existingMockVerifier.address)) !== '0x') { - console.log('MockRISC0Verifier already deployed at:', existingMockVerifier.address) - return existingMockVerifier.address - } - const mockVerifierFactory = await ethers.getContractFactory('MockRISC0Verifier') - const mockVerifier = await mockVerifierFactory.deploy() - await mockVerifier.waitForDeployment() - const mockVerifierAddress = await mockVerifier.getAddress() + const { receipt: verifier, halo2Verifier, halo2RuntimeCodeHash, appExeCommit, appVmCommit } = await deployOpenVmReceiptVerifier(ethers) + storeDeploymentArgs( + { address: halo2Verifier, blockNumber: await ethers.provider.getBlockNumber(), bytecodeHash: halo2RuntimeCodeHash }, + 'OpenVmHalo2Verifier', + chain, + ) + const address = await verifier.getAddress() storeDeploymentArgs( { - address: mockVerifierAddress, + address, blockNumber: await ethers.provider.getBlockNumber(), + constructorArgs: { verifier: halo2Verifier, appExeCommit, appVmCommit }, }, - 'MockRISC0Verifier', + 'OpenVmReceiptVerifier', chain, ) - - return mockVerifierAddress + return address } diff --git a/examples/CRISP/packages/crisp-contracts/hardhat.config.ts b/examples/CRISP/packages/crisp-contracts/hardhat.config.ts index 54f0063d49..8c0ea34359 100644 --- a/examples/CRISP/packages/crisp-contracts/hardhat.config.ts +++ b/examples/CRISP/packages/crisp-contracts/hardhat.config.ts @@ -78,7 +78,7 @@ const config: HardhatUserConfig = { }, chainId: chainIds.hardhat, type: 'http', - url: 'http://localhost:8545', + url: process.env.LOCAL_RPC_URL ?? 'http://localhost:8545', timeout: 60000, }, ganache: { @@ -125,6 +125,8 @@ const config: HardhatUserConfig = { '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol', '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol', '@interfold/contracts/contracts/Interfold.sol', + '@interfold/contracts/contracts/E3RefundManager.sol', + '@interfold/contracts/contracts/registry/NodeReleaseRegistry.sol', '@interfold/contracts/contracts/lib/InterfoldLifecycle.sol', '@interfold/contracts/contracts/lib/InterfoldPricing.sol', '@interfold/contracts/contracts/lib/BondingAssetLib.sol', @@ -148,12 +150,14 @@ const config: HardhatUserConfig = { '@interfold/contracts/contracts/test/MockDecryptionVerifier.sol', '@interfold/contracts/contracts/test/MockDkgFoldAttestationVerifier.sol', '@interfold/contracts/contracts/test/MockPkVerifier.sol', + '@interfold/contracts/contracts/test/MockRandomnessProvider.sol', '@interfold/contracts/contracts/test/MockE3Program.sol', '@interfold/contracts/contracts/test/MockE3ProgramHarness.sol', '@interfold/contracts/contracts/test/MockSlashingVerifier.sol', '@interfold/contracts/contracts/test/MockStableToken.sol', '@interfold/contracts/contracts/verifiers/bfv/BfvDecryptionVerifier.sol', - '@interfold/contracts/contracts/verifiers/bfv/Risc0BfvCiphertextVerifier.sol', + '@interfold/contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol', + '@interfold/contracts/contracts/verifiers/OpenVmReceiptVerifier.sol', '@interfold/contracts/contracts/verifiers/bfv/BfvPkVerifier.sol', '@interfold/contracts/contracts/verifiers/AvailVectorXDataAvailabilityVerifier.sol', '@interfold/contracts/contracts/verifiers/bfv/honk/DkgAggregatorVerifier.sol', diff --git a/examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum b/examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum deleted file mode 160000 index 32aa0b6f23..0000000000 --- a/examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 32aa0b6f23ddd02dd93fc71717667606e5c7db86 diff --git a/examples/CRISP/packages/crisp-contracts/package.json b/examples/CRISP/packages/crisp-contracts/package.json index ae6330911a..d2adf9fa90 100644 --- a/examples/CRISP/packages/crisp-contracts/package.json +++ b/examples/CRISP/packages/crisp-contracts/package.json @@ -40,7 +40,7 @@ "governance:builder": "hardhat run deploy/create-governance-builder.ts", "test": "hardhat test mocha", "check:test-legs": "node scripts/check-test-legs.mjs", - "test:unit": "pnpm check:test-legs && hardhat test mocha tests/census-mode.test.ts tests/crisp.journal.test.ts tests/input-availability-flow.test.ts tests/input-leaf.test.ts tests/interfold-binding.test.ts tests/self-registry.test.ts tests/tally.decoding.test.ts", + "test:unit": "pnpm check:test-legs && hardhat test mocha tests/census-mode.test.ts tests/crisp.journal.test.ts tests/input-availability-flow.test.ts tests/input-leaf.test.ts tests/interfold-binding.test.ts tests/openvm-proof.test.ts tests/openvm-receipt.test.ts tests/openvm-service.test.ts tests/self-registry.test.ts tests/tally.decoding.test.ts", "test:input-tree": "hardhat test mocha tests/input-tree-e2e.test.ts", "test:input-tree:poisoned-parent": "hardhat test mocha --grep \"lets an honest mask follow\" -- tests/input-tree-e2e.test.ts", "test:input-tree:canonical": "hardhat test mocha --grep \"^(?!.*lets an honest mask follow)\" -- tests/input-tree-e2e.test.ts", diff --git a/examples/CRISP/packages/crisp-contracts/remappings.txt b/examples/CRISP/packages/crisp-contracts/remappings.txt index 970b77ad65..2ca553b4f7 100644 --- a/examples/CRISP/packages/crisp-contracts/remappings.txt +++ b/examples/CRISP/packages/crisp-contracts/remappings.txt @@ -1,7 +1,5 @@ -forge-std/=lib/risc0-ethereum/lib/forge-std/src/ -risc0/=lib/risc0-ethereum/contracts/src/ @interfold/contracts/=node_modules/@interfold/contracts/ solady/=node_modules/solady/ @zk-kit/lazy-imt.sol=node_modules/@zk-kit/lazy-imt.sol poseidon-solidity/=node_modules/poseidon-solidity/ -@openzeppelin/=node_modules/@openzeppelin/ \ No newline at end of file +@openzeppelin/=node_modules/@openzeppelin/ diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.journal.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.journal.test.ts index 11bed7f5be..0596ebd081 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.journal.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.journal.test.ts @@ -4,10 +4,10 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { deployCRISPProgram, deployHonkVerifier, deployMockInterfold, deployMockRISC0Verifier, ethers } from './utils' +import { deployCRISPProgram, deployHonkVerifier, deployMockInterfold, deployMockComputeReceiptVerifier, ethers } from './utils' describe('CRISP journal', () => { - it('should match the journal returned by the RISC Zero guest', async () => { + it('should match the journal returned by the OpenVM guest', async () => { const ciphertextHash = ethers.hexlify(Uint8Array.from({ length: 32 }, (_, index) => index)) const ciphertextCommitment = ethers.hexlify(Uint8Array.from({ length: 32 }, (_, index) => index + 32)) const paramsHash = ethers.keccak256('0x') @@ -15,36 +15,26 @@ describe('CRISP journal', () => { const committeePublicKey = `0x${'33'.repeat(32)}` const encryptionSchemeId = ethers.keccak256(ethers.toUtf8Bytes('fhe.rs:BFV')) - const encodeRisc0Vec32 = (value: string) => { - const encoded = [32, 0, 0, 0] - for (const byte of ethers.getBytes(value)) { - encoded.push(byte, 0, 0, 0) - } - return Uint8Array.from(encoded) - } - const mockInterfold = await deployMockInterfold() await mockInterfold.setCommitteePublicKey(committeePublicKey) const chainId = (await ethers.provider.getNetwork()).chainId - const journal = ethers.concat( - [ - ethers.zeroPadValue(ethers.toBeHex(chainId), 32), - ethers.zeroPadValue(await mockInterfold.getAddress(), 32), - ethers.zeroPadValue(ethers.toBeHex(0), 32), - encryptionSchemeId, - committeePublicKey, - ciphertextHash, - ciphertextCommitment, - paramsHash, - inputRoot, - ].map(encodeRisc0Vec32), - ) + const journal = ethers.concat([ + ethers.zeroPadValue(ethers.toBeHex(chainId), 32), + ethers.zeroPadValue(await mockInterfold.getAddress(), 32), + ethers.zeroPadValue(ethers.toBeHex(0), 32), + encryptionSchemeId, + committeePublicKey, + ciphertextHash, + ciphertextCommitment, + paramsHash, + inputRoot, + ]) const journalDigest = ethers.sha256(journal) const honkVerifier = await deployHonkVerifier() - const risc0Verifier = await deployMockRISC0Verifier() - await risc0Verifier.setExpectedJournalDigest(journalDigest) - const program = await deployCRISPProgram({ mockInterfold, honkVerifier, risc0Verifier }) + const computeVerifier = await deployMockComputeReceiptVerifier() + await computeVerifier.setExpectedJournalDigest(journalDigest) + const program = await deployCRISPProgram({ mockInterfold, honkVerifier, computeVerifier }) const e3Id = await mockInterfold.nextE3Id() await mockInterfold.request(await program.getAddress()) diff --git a/examples/CRISP/packages/crisp-contracts/tests/openvm-proof.test.ts b/examples/CRISP/packages/crisp-contracts/tests/openvm-proof.test.ts new file mode 100644 index 0000000000..69f1c2ef07 --- /dev/null +++ b/examples/CRISP/packages/crisp-contracts/tests/openvm-proof.test.ts @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +import { expect } from 'chai' +import { createHash } from 'node:crypto' +import { readFileSync } from 'node:fs' +import { network } from 'hardhat' +import { deployOpenVmReceiptVerifier } from '../../../../../packages/interfold-contracts/scripts/openVm' + +const names = ['OPENVM_TEST_IDENTITY', 'OPENVM_TEST_JOURNAL', 'OPENVM_TEST_VERIFIER', 'OPENVM_TEST_VERIFIER_SHA256'] as const +const enabled = names.every((name) => process.env[name]) && Boolean(process.env.OPENVM_TEST_PROOF || process.env.OPENVM_TEST_SEAL) +if (process.env.OPENVM_REQUIRE_PROOF_TEST === '1' && !enabled) { + throw new Error(`Set ${names.join(', ')} and either OPENVM_TEST_PROOF or OPENVM_TEST_SEAL`) +} +;(enabled ? describe : describe.skip)('OpenVM real EVM proof', function () { + this.timeout(300_000) + it('accepts the proof and rejects changed journal words, identities, and proof bytes', async () => { + const connection = await network.connect() + expect(connection.networkConfig.type).to.equal('edr-simulated') + const { ethers } = connection + const json = (name: (typeof names)[number]) => JSON.parse(readFileSync(process.env[name]!, 'utf8')) + const identity = json('OPENVM_TEST_IDENTITY') + const commits = identity.app_commit ?? identity + const journal = readFileSync(process.env.OPENVM_TEST_JOURNAL!) + const artifact = readFileSync(process.env.OPENVM_TEST_VERIFIER!) + expect(createHash('sha256').update(artifact).digest('hex')).to.equal(process.env.OPENVM_TEST_VERIFIER_SHA256) + expect(journal.length).to.equal(288) + const words = Array.from({ length: 9 }, (_, i) => ethers.hexlify(journal.subarray(i * 32, (i + 1) * 32))) + const abi = ethers.AbiCoder.defaultAbiCoder() + let data: string + if (process.env.OPENVM_TEST_SEAL) { + const encoded = ethers.hexlify(readFileSync(process.env.OPENVM_TEST_SEAL)) + const decoded = abi.decode(['uint8', 'bytes', 'bytes32[9]'], encoded) + expect(decoded[0]).to.equal(1n) + expect(Array.from(decoded[2])).to.deep.equal(words) + data = decoded[1] + expect(abi.encode(['uint8', 'bytes', 'bytes32[9]'], [1, data, words])).to.equal(encoded) + } else { + const proof = JSON.parse(readFileSync(process.env.OPENVM_TEST_PROOF!, 'utf8')) + expect(proof.app_exe_commit).to.equal(commits.app_exe_commit) + expect(proof.app_vm_commit).to.equal(commits.app_vm_commit) + expect(proof.user_public_values).to.equal(ethers.sha256(journal)) + data = ethers.concat([proof.proof_data.accumulator, proof.proof_data.proof]) + } + const { receipt, halo2Verifier } = await deployOpenVmReceiptVerifier(ethers, { + OPENVM_VERIFIER_ARTIFACT: process.env.OPENVM_TEST_VERIFIER, + OPENVM_VERIFIER_SHA256: process.env.OPENVM_TEST_VERIFIER_SHA256, + OPENVM_APP_EXE_COMMIT: commits.app_exe_commit, + OPENVM_APP_VM_COMMIT: commits.app_vm_commit, + }) + const seal = (values = words, bytes = data) => abi.encode(['uint8', 'bytes', 'bytes32[9]'], [1, bytes, values]) + const digest = (values = words) => ethers.sha256(abi.encode(['bytes32[9]'], [values])) + const imageId = await receipt.imageId() + await expect(receipt.verify(seal(), imageId, digest())).not.to.revert(ethers) + const protocol = await ethers.deployContract('OpenVmBfvCiphertextVerifier', [await receipt.getAddress(), imageId]) + expect(BigInt(words[0])).to.equal((await ethers.provider.getNetwork()).chainId) + const envelope = abi.encode(['bytes', 'bytes32', 'bytes32'], [seal(), words[7], words[8]]) + const result = await ethers.provider.call({ + to: protocol.target, + from: ethers.getAddress(ethers.dataSlice(words[1], 12)), + data: protocol.interface.encodeFunctionData('verify', [BigInt(words[2]), words[3], words[7], words[4], words[5], words[6], envelope]), + }) + expect(abi.decode(['bool'], result)[0]).to.equal(true) + for (let i = 0; i < words.length; i++) { + const changed = [...words] + changed[i] = ethers.zeroPadValue(ethers.toBeHex(BigInt(changed[i]) ^ 1n), 32) + await expect(receipt.verify(seal(changed), imageId, digest(changed))).to.revert(ethers) + } + const changed = ethers.getBytes(data) + changed[changed.length - 1] ^= 1 + await expect(receipt.verify(seal(words, ethers.hexlify(changed)), imageId, digest())).to.revert(ethers) + for (const field of ['app_exe_commit', 'app_vm_commit'] as const) { + const other = { ...commits, [field]: ethers.zeroPadValue(ethers.toBeHex(BigInt(commits[field]) ^ 1n), 32) } + const wrong = await ethers.deployContract('OpenVmReceiptVerifier', [halo2Verifier, other.app_exe_commit, other.app_vm_commit]) + await expect(wrong.verify(seal(), await wrong.imageId(), digest())).to.revert(ethers) + } + }) +}) diff --git a/examples/CRISP/packages/crisp-contracts/tests/openvm-receipt.test.ts b/examples/CRISP/packages/crisp-contracts/tests/openvm-receipt.test.ts new file mode 100644 index 0000000000..ba874d494c --- /dev/null +++ b/examples/CRISP/packages/crisp-contracts/tests/openvm-receipt.test.ts @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +import { expect } from 'chai' +import { network } from 'hardhat' + +const { ethers } = await network.connect() + +const abi = ethers.AbiCoder.defaultAbiCoder() +const word = (value: number | bigint) => ethers.zeroPadValue(ethers.toBeHex(value), 32) +const exeCommit = word(1) +const vmCommit = word(2) +const proofData = `0x${'ab'.repeat(1760)}` +const seal = (words: string[], data = proofData, version = 1) => abi.encode(['uint8', 'bytes', 'bytes32[9]'], [version, data, words]) +const publicValues = (words: string[]) => ethers.sha256(abi.encode(['bytes32[9]'], [words])) + +const journalDigest = publicValues + +async function deployAdapter() { + const verifier = await ethers.deployContract('MockOpenVmCallVerifier') + const adapter = await ethers.deployContract('OpenVmReceiptVerifier', [await verifier.getAddress(), exeCommit, vmCommit]) + return { verifier, adapter, imageId: await adapter.imageId() } +} + +describe('OpenVM receipt verifier (call oracle, not proof verification)', () => { + it('binds all nine journal words to the OpenVM digest', async () => { + const { verifier, adapter, imageId } = await deployAdapter() + const words = Array.from({ length: 9 }, (_, index) => word(index + 1)) + await verifier.setExpectedCall(publicValues(words), proofData, exeCommit, vmCommit) + await expect(adapter.verify(seal(words), imageId, journalDigest(words))).not.to.revert(ethers) + + for (let index = 0; index < words.length; index++) { + const changed = [...words] + changed[index] = word(BigInt(changed[index]) ^ 1n) + await expect(adapter.verify(seal(changed), imageId, journalDigest(words))).to.be.revertedWithCustomError( + adapter, + 'JournalDigestMismatch', + ) + await expect(adapter.verify(seal(changed), imageId, journalDigest(changed))).to.be.revertedWithCustomError( + verifier, + 'UnexpectedOpenVmCall', + ) + } + }) + + it('binds the image identity to both commitments and the verifier', async () => { + const { verifier, adapter, imageId } = await deployAdapter() + expect(imageId).to.equal( + ethers.keccak256( + abi.encode( + ['bytes32', 'address', 'bytes32', 'bytes32'], + [ethers.keccak256(ethers.toUtf8Bytes('INTERFOLD_OPENVM_RECEIPT_V1')), await verifier.getAddress(), exeCommit, vmCommit], + ), + ), + ) + const secondVerifier = await ethers.deployContract('MockOpenVmCallVerifier') + const words = Array.from({ length: 9 }, (_, index) => word(index)) + await verifier.setExpectedCall(publicValues(words), proofData, exeCommit, vmCommit) + for (const args of [ + [await secondVerifier.getAddress(), exeCommit, vmCommit], + [await verifier.getAddress(), word(3), vmCommit], + [await verifier.getAddress(), exeCommit, word(3)], + ]) { + const other = await ethers.deployContract('OpenVmReceiptVerifier', args) + expect(await other.imageId()).not.to.equal(imageId) + await expect(other.verify(seal(words), await other.imageId(), journalDigest(words))).to.be.revertedWithCustomError( + verifier, + 'UnexpectedOpenVmCall', + ) + } + await expect(adapter.verify(seal(words), word(100), journalDigest(words))).to.be.revertedWithCustomError(adapter, 'WrongImageId') + }) + + it('rejects invalid configuration and noncanonical seals', async () => { + const { verifier, adapter, imageId } = await deployAdapter() + const [signer] = await ethers.getSigners() + const factory = await ethers.getContractFactory('OpenVmReceiptVerifier') + await expect(factory.deploy(await signer.getAddress(), exeCommit, vmCommit)).to.be.revertedWithCustomError(adapter, 'InvalidVerifier') + const modulus = '0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001' + for (const [exe, vm] of [ + [word(0), vmCommit], + [exeCommit, word(0)], + [modulus, vmCommit], + [exeCommit, modulus], + ]) { + await expect(factory.deploy(await verifier.getAddress(), exe, vm)).to.be.revertedWithCustomError(adapter, 'InvalidAppCommitment') + } + const words = Array.from({ length: 9 }, (_, index) => word(index)) + const digest = journalDigest(words) + await verifier.setExpectedCall(publicValues(words), proofData, exeCommit, vmCommit) + await expect(adapter.verify(seal(words, proofData, 2), imageId, digest)).to.be.revertedWithCustomError(adapter, 'InvalidSealVersion') + await expect(adapter.verify(`${seal(words)}00`, imageId, digest)).to.be.revertedWithCustomError(adapter, 'InvalidSealEncoding') + await expect(adapter.verify(seal(words, '0x'), imageId, digest)).to.be.revertedWithCustomError(adapter, 'InvalidProofDataLength') + await expect(adapter.verify('0x', imageId, digest)).to.revert(ethers) + await expect(adapter.verify(seal(words, `0x${'cd'.repeat(1760)}`), imageId, digest)).to.be.revertedWithCustomError( + verifier, + 'UnexpectedOpenVmCall', + ) + }) + + it('preserves the protocol and CRISP application verification calls', async () => { + const { verifier, adapter, imageId } = await deployAdapter() + const [owner] = await ethers.getSigners() + const controller = await ethers.deployContract('MockInterfold') + const honk = await ethers.deployContract('MockHonkVerifier') + const availability = await ethers.deployContract('MockCrispDataAvailabilityVerifier') + const poseidon = await ethers.deployContract('PoseidonT3') + const factory = await ethers.getContractFactory('CRISPProgram', { + libraries: { + 'npm/poseidon-solidity@0.0.5/PoseidonT3.sol:PoseidonT3': await poseidon.getAddress(), + }, + }) + const program = await factory.deploy( + await owner.getAddress(), + await adapter.getAddress(), + await honk.getAddress(), + await honk.getAddress(), + await availability.getAddress(), + 0, + await owner.getAddress(), + imageId, + ) + await controller.registerE3Program(await program.getAddress()) + await program.bindInterfold(await controller.getAddress()) + await controller.setCommitteePublicKey(word(55)) + await controller.request(await program.getAddress()) + const protocol = await ethers.deployContract('OpenVmBfvCiphertextVerifier', [await adapter.getAddress(), imageId]) + + const words = [ + word(31337), + ethers.zeroPadValue(await controller.getAddress(), 32), + word(0), + await controller.ENCRYPTION_SCHEME_ID(), + word(55), + word(66), + word(77), + ethers.keccak256('0x'), + '0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864', + ] + await verifier.setExpectedCall(publicValues(words), proofData, exeCommit, vmCommit) + const envelope = (sealWords = words, paramsHash = words[7], inputRoot = words[8]) => + abi.encode(['bytes', 'bytes32', 'bytes32'], [seal(sealWords), paramsHash, inputRoot]) + const protocolCall = (values = words, proof = envelope(), caller?: string) => + ethers.provider.call({ + to: protocol.target, + from: caller ?? controller.target, + data: protocol.interface.encodeFunctionData('verify', [ + BigInt(values[2]), + values[3], + values[7], + values[4], + values[5], + values[6], + proof, + ]), + }) + expect(abi.decode(['bool'], await protocolCall())[0]).to.equal(true) + expect(await program.verify(0, words[5], words[6], envelope())).to.equal(true) + + for (const index of [2, 3, 4, 5, 6]) { + const changed = [...words] + changed[index] = word(BigInt(changed[index]) ^ 1n) + await expect(protocolCall(changed)).to.be.revertedWithCustomError(adapter, 'JournalDigestMismatch') + } + expect(abi.decode(['bool'], await protocolCall([...words.slice(0, 7), word(999), words[8]]))[0]).to.equal(false) + await expect(protocolCall(words, envelope(), await owner.getAddress())).to.be.revertedWithCustomError(adapter, 'JournalDigestMismatch') + await expect(program.verify(0, word(999), words[6], envelope())).to.be.revertedWithCustomError(adapter, 'JournalDigestMismatch') + await expect(program.verify(0, words[5], word(999), envelope())).to.be.revertedWithCustomError(adapter, 'JournalDigestMismatch') + await expect(program.verify(0, words[5], words[6], envelope(words, word(999)))).to.be.revertedWithCustomError( + program, + 'InvalidComputeContext', + ) + await expect(program.verify(0, words[5], words[6], envelope(words, words[7], word(999)))).to.be.revertedWithCustomError( + program, + 'InvalidComputeContext', + ) + const changed = [...words] + changed[8] = word(999) + await expect(protocolCall(words, envelope(changed, words[7], changed[8]))).to.be.revertedWithCustomError( + verifier, + 'UnexpectedOpenVmCall', + ) + await program.setImageId(word(999)) + await expect(program.verify(0, words[5], words[6], envelope())).to.be.revertedWithCustomError(adapter, 'WrongImageId') + }) +}) diff --git a/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts b/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts new file mode 100644 index 0000000000..a73f46d13c --- /dev/null +++ b/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +import { expect } from 'chai' +import { createHash } from 'node:crypto' +import { spawn, type ChildProcess } from 'node:child_process' +import { createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import path from 'node:path' +import { setTimeout as delay } from 'node:timers/promises' + +const enabled = process.env.OPENVM_E2E_ENABLED === '1' +const required = [ + 'LOCAL_RPC_URL', + 'OPENVM_E2E_FIXTURE', + 'OPENVM_E2E_SERVER', + 'OPENVM_E2E_OUTPUT', + 'OPENVM_E2E_PROGRAM_URL', + 'OPENVM_E2E_CALLBACK_URL', + 'OPENVM_TEST_IDENTITY', + 'OPENVM_TEST_VERIFIER', + 'OPENVM_TEST_VERIFIER_SHA256', +] as const +if (enabled) { + for (const name of required) if (!process.env[name]) throw new Error(`Set ${name}`) + const rpc = new URL(process.env.LOCAL_RPC_URL!) + if (!['127.0.0.1', 'localhost', '[::1]'].includes(rpc.hostname)) throw new Error('The service test requires a loopback RPC') +} + +;(enabled ? describe : describe.skip)('OpenVM live CRISP compute flow', function () { + this.timeout(4 * 60 * 60 * 1000) + + it('dispatches indexed ballots over HTTP and automatically publishes a newly generated proof', async () => { + const { connection, ethers, networkHelpers } = await import('../../../../../packages/interfold-contracts/test/fixtures/connection') + expect(connection.networkConfig.type).to.equal('http') + expect((await ethers.provider.getNetwork()).chainId).to.equal(31337n) + const { deployInterfoldSystem } = await import('../../../../../packages/interfold-contracts/test/fixtures/system') + const { buildMockDkgAttestationFixtureData } = await import('../../../../../packages/interfold-contracts/test/fixtures/dkgAttestation') + const { BFV_PARAMS_SECURE, PRODUCTION_CRYPTO_CONFIG_ID, ENCRYPTION_SCHEME_ID } = await import( + '../../../../../packages/interfold-contracts/test/fixtures/constants' + ) + const { time } = networkHelpers + const abi = ethers.AbiCoder.defaultAbiCoder() + const directory = path.resolve(process.env.OPENVM_E2E_OUTPUT!) + if (existsSync(directory)) throw new Error('The service-test output directory must not already exist') + mkdirSync(directory, { recursive: true }) + const fixtureDirectory = path.resolve(process.env.OPENVM_E2E_FIXTURE!) + const fixture = JSON.parse(readFileSync(path.join(fixtureDirectory, 'fixture.json'), 'utf8')) + expect(fixture.params).to.equal(BFV_PARAMS_SECURE) + expect(fixture.native_tally_checked).to.equal(true) + const identity = JSON.parse(readFileSync(process.env.OPENVM_TEST_IDENTITY!, 'utf8')) + const commits = identity.app_commit ?? identity + const verifierBytes = readFileSync(process.env.OPENVM_TEST_VERIFIER!) + expect(createHash('sha256').update(verifierBytes).digest('hex')).to.equal(process.env.OPENVM_TEST_VERIFIER_SHA256) + const report: Record = { + started_at: new Date().toISOString(), + input_count: fixture.inputs.length, + preset: fixture.preset, + network: 'local-http-evm', + status: 'deploying', + real_compute_proof_verified: false, + callback_http_delivery_tested: false, + automatic_ciphertext_publication: false, + production_deployment: false, + mocked_dependencies: [ + 'randomness', + 'DKG proof', + 'DKG fold attestations', + 'ballot proofs and census', + 'data availability', + 'threshold decryption proof', + ], + } + const save = (status: string, fields: Record = {}) => { + Object.assign(report, fields, { status, updated_at: new Date().toISOString() }) + writeFileSync(path.join(directory, 'report.json'), JSON.stringify(report, null, 2)) + console.log(`OpenVM service round: ${status}`) + } + let server: ChildProcess | undefined + const log = createWriteStream(path.join(directory, 'crisp-server.log')) + const localServer = new URL(process.env.OPENVM_E2E_LOCAL_SERVER_URL ?? 'http://127.0.0.1:14000') + if (!['127.0.0.1', 'localhost', '[::1]'].includes(localServer.hostname)) throw new Error('The CRISP test listener must use loopback') + async function waitFor(label: string, check: () => Promise, timeoutMs = 120_000) { + const end = Date.now() + timeoutMs + let last: unknown + while (Date.now() < end) { + if (server && server.exitCode !== null) throw new Error(`CRISP exited with ${server.exitCode}; see crisp-server.log`) + try { + if (await check()) return + } catch (error) { + last = error + } + await delay(1000) + } + throw new Error(`Timed out waiting for ${label}${last ? `: ${last}` : ''}`) + } + const post = (route: string, body: unknown) => + fetch(new URL(route, localServer), { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body), + signal: AbortSignal.timeout(60_000), + }) + try { + const health = await fetch(new URL('/health', process.env.OPENVM_E2E_PROGRAM_URL!), { signal: AbortSignal.timeout(30_000) }) + expect(health.ok).to.equal(true) + const system = await deployInterfoldSystem({ + deploymentId: `openvm-service-${Date.now()}`, + timeoutConfig: { dkgWindow: 3600, computeWindow: 21600, decryptionWindow: 3600 }, + }) + const { owner, operators, interfold, ciphernodeRegistry: registry, usdcToken } = system + const relay = ethers.Wallet.createRandom().connect(ethers.provider) + await (await owner.sendTransaction({ to: relay.address, value: ethers.parseEther('100') })).wait() + const halo2 = await new ethers.ContractFactory( + ['function verify(bytes,bytes,bytes32,bytes32) view'], + `0x${JSON.parse(verifierBytes.toString()).bytecode}`, + owner, + ).deploy() + await halo2.waitForDeployment() + const receipt = await ethers.deployContract('OpenVmReceiptVerifier', [ + await halo2.getAddress(), + commits.app_exe_commit, + commits.app_vm_commit, + ]) + const identityId = await receipt.imageId() + const protocol = await ethers.deployContract('OpenVmBfvCiphertextVerifier', [await receipt.getAddress(), identityId]) + const honk = await ethers.deployContract('MockHonkVerifier') + const availability = await ethers.deployContract('MockCrispDataAvailabilityVerifier') + const poseidon = await ethers.deployContract('PoseidonT3') + const program = await ( + await ethers.getContractFactory('CRISPProgram', { + libraries: { 'npm/poseidon-solidity@0.0.5/PoseidonT3.sol:PoseidonT3': await poseidon.getAddress() }, + }) + ).deploy( + relay.address, + await receipt.getAddress(), + await honk.getAddress(), + await honk.getAddress(), + await availability.getAddress(), + 0, + relay.address, + identityId, + ) + await (await interfold.registerE3Program(await program.getAddress())).wait() + await (await program.connect(relay).bindInterfold(await interfold.getAddress())).wait() + await (await interfold.setParamSet(1, BFV_PARAMS_SECURE)).wait() + await (await interfold.setCiphertextVerifier(ENCRYPTION_SCHEME_ID, await protocol.getAddress())).wait() + const rpc = process.env.LOCAL_RPC_URL! + server = spawn(path.resolve(process.env.OPENVM_E2E_SERVER!), [], { + cwd: directory, + env: { + PATH: process.env.PATH, + RUST_LOG: 'info', + RUST_BACKTRACE: '1', + PRIVATE_KEY: relay.privateKey, + INTERFOLD_SERVER_URL: process.env.OPENVM_E2E_CALLBACK_URL!, + CRISP_BIND_ADDR: `${localServer.hostname}:${localServer.port}`, + PROGRAM_SERVER_URL: process.env.OPENVM_E2E_PROGRAM_URL!, + HTTP_RPC_URL: rpc, + WS_RPC_URL: rpc.replace(/^http/, 'ws'), + CHAIN_ID: '31337', + INTERFOLD_ADDRESS: await interfold.getAddress(), + E3_PROGRAM_ADDRESS: await program.getAddress(), + CIPHERNODE_REGISTRY_ADDRESS: await registry.getAddress(), + FEE_TOKEN_ADDRESS: await usdcToken.getAddress(), + DATA_AVAILABILITY_MODE: 'mock', + E3_PARAM_SET: '1', + E3_COMMITTEE_SIZE: '0', + E3_DURATION: '3600', + E3_COMPUTE_PROVIDER_NAME: 'OpenVM', + E3_COMPUTE_PROVIDER_PARALLEL: 'false', + E3_COMPUTE_PROVIDER_BATCH_SIZE: '1', + }, + stdio: ['ignore', 'pipe', 'pipe'], + }) + server.stdout!.pipe(log, { end: false }) + server.stderr!.pipe(log, { end: false }) + server.once('error', (error) => log.write(`Server spawn failed: ${error}\n`)) + await waitFor('CRISP listener', async () => { + await fetch(localServer, { signal: AbortSignal.timeout(2000) }) + return true + }) + await delay(2000) + const start = Number(await time.latest()) + 60 + const end = start + 3600 + const request: typeof system.request = { + ...system.request, + e3Program: await program.getAddress(), + inputWindow: [start, end], + paramSet: 1, + expectedCryptoConfigId: PRODUCTION_CRYPTO_CONFIG_ID, + customParams: abi.encode( + ['address', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256'], + [ethers.ZeroAddress, 0, 2, 0, 3, 0, 1], + ), + } + const e3Id = await interfold.nexte3Id() + const fee = await interfold.getE3Quote(request) + await (await usdcToken.approve(await interfold.getAddress(), fee)).wait() + await (await interfold.request({ ...request, maxFee: fee })).wait() + save('committee setup', { + e3_id: e3Id.toString(), + interfold: await interfold.getAddress(), + program: await program.getAddress(), + relay: relay.address, + receipt_verifier: await receipt.getAddress(), + protocol_verifier: await protocol.getAddress(), + halo2_verifier: await halo2.getAddress(), + }) + await time.increase(1) + for (const operator of operators) await (await registry.connect(operator).submitTicket(e3Id, 1)).wait() + await time.setNextBlockTimestamp((await registry.getCommitteeDeadline(e3Id)) + 1n) + await (await registry.finalizeCommittee(e3Id)).wait() + const keyCommitment = fixture.public_key_commitment + const dkg = await buildMockDkgAttestationFixtureData( + operators, + e3Id, + keyCommitment, + await registry.dkgFoldAttestationVerifier(), + await registry.getAddress(), + ) + await (await registry.publishCommittee(e3Id, keyCommitment, dkg.proof, dkg.bundle)).wait() + const publicKey = readFileSync(path.join(fixtureDirectory, 'public-key.bin')) + const chunkSize = 90 * 1024 + for (let i = 0; i < Math.ceil(publicKey.length / chunkSize); i++) { + await ( + await registry + .connect(operators[0]) + .publishCommitteePublicKey( + e3Id, + ethers.keccak256(publicKey), + i, + Math.ceil(publicKey.length / chunkSize), + publicKey.length, + publicKey.subarray(i * chunkSize, (i + 1) * chunkSize), + ) + ).wait() + } + await waitFor('indexed round and validated committee key', async () => (await post('/state/lite', { round_id: e3Id.toString() })).ok) + await waitFor('server census publication', async () => (await program.getRoundData(e3Id)).merkleRoot !== 0n) + if (Number(await time.latest()) < start) await time.increaseTo(start) + save('submitting ballots through CRISP HTTP') + for (const entry of fixture.inputs) { + const bytes = readFileSync(path.join(fixtureDirectory, entry.file)) + expect(ethers.keccak256(bytes)).to.equal(entry.content_hash) + const encoded = abi.encode( + ['bytes', 'address', 'bytes32', 'bytes32', 'uint40', 'bytes'], + ['0x01', entry.slot, entry.commitment, entry.content_hash, entry.parent_index_plus_one, bytes], + ) + let response = await post('/voting/broadcast', { round_id: e3Id.toString(), encoded_proof: encoded }) + while (response.status === 429) { + await delay(10_000) + response = await post('/voting/broadcast', { round_id: e3Id.toString(), encoded_proof: encoded }) + } + const body = await response.text() + expect(response.ok, body).to.equal(true) + await waitFor(`input ${entry.index} finalization`, async () => + program.isInputPublished(e3Id, entry.content_hash, entry.commitment, entry.slot, entry.parent_index_plus_one), + ) + if ((entry.index + 1) % 10 === 0) save('submitting ballots through CRISP HTTP', { finalized_inputs: entry.index + 1 }) + } + const round = await program.getRoundData(e3Id) + expect(round.numberOfVotes).to.equal(BigInt(fixture.inputs.length)) + expect(ethers.zeroPadValue(ethers.toBeHex(round.inputRoot), 32)).to.equal(fixture.input_root) + expect(await program.pendingInputCount(e3Id)).to.equal(0n) + const proofStarted = Date.now() + await time.increaseTo(end + 1) + save('waiting for live OpenVM computation and callback', { + input_root: fixture.input_root, + compute_started_at: new Date().toISOString(), + }) + await waitFor( + 'automatic ciphertext publication', + async () => { + await ethers.provider.send('evm_mine', []) + return (await interfold.getE3Stage(e3Id)) === 4n + }, + 3 * 60 * 60 * 1000, + ) + const output = await interfold.getE3(e3Id) + expect(output.ciphertextOutput).to.equal(fixture.ciphertext_hash) + expect(output.ciphertextCommitment).to.equal(fixture.ciphertext_commitment) + const events = await interfold.queryFilter(interfold.filters.CiphertextOutputReferencePublished(e3Id)) + expect(events).to.have.length(1) + const publication = await ethers.provider.getTransaction(events[0].transactionHash) + expect(publication!.from).to.equal(relay.address) + const publicationReceipt = await publication!.wait() + expect(publicationReceipt!.status).to.equal(1) + const decoded = interfold.interface.parseTransaction({ data: publication!.data })! + const reference = abi.decode(['tuple(bytes32,bytes32,bytes,bytes)'], decoded.args[1])[0] + const computeProof = reference[2] + const envelope = abi.decode(['bytes', 'bytes32', 'bytes32'], computeProof) + const seal = abi.decode(['uint8', 'bytes', 'bytes32[9]'], envelope[0]) + expect(seal[2][8]).to.equal(fixture.input_root) + expect(seal[2][4]).to.equal(keyCommitment) + await expect(receipt.verify(envelope[0], identityId, ethers.sha256(abi.encode(['bytes32[9]'], [seal[2]])))).not.to.revert(ethers) + const changed = ethers.getBytes(seal[1]) + changed[changed.length - 1] ^= 1 + const invalidSeal = abi.encode(['uint8', 'bytes', 'bytes32[9]'], [1, changed, seal[2]]) + writeFileSync(path.join(directory, 'seal.bin'), ethers.getBytes(envelope[0])) + save('ciphertext published and verified', { + real_compute_proof_verified: true, + callback_http_delivery_tested: true, + automatic_ciphertext_publication: true, + compute_to_publication_ms: Date.now() - proofStarted, + publication_tx: publication!.hash, + publication_gas: publicationReceipt!.gasUsed.toString(), + app_exe_commit: commits.app_exe_commit, + app_vm_commit: commits.app_vm_commit, + }) + // Hardhat's HTTP node can report a precompile rejection as an RPC internal error. + // The execution trace must show an EVM revert, not merely a failed RPC request. + const trace = await ethers.provider.send('debug_traceCall', [ + { + to: await receipt.getAddress(), + data: receipt.interface.encodeFunctionData('verify', [ + invalidSeal, + identityId, + ethers.sha256(abi.encode(['bytes32[9]'], [seal[2]])), + ]), + }, + 'latest', + { disableMemory: true, disableStack: true, disableStorage: true }, + ]) + expect(trace.failed).to.equal(true) + expect(trace.structLogs.at(-1).op).to.equal('REVERT') + + // Finish the local lifecycle with native plaintext and the declared decryption mock. + // This step does not test distributed decryption or its recursive proof. + const escrow = await interfold.e3Payments(e3Id) + const pricing = await interfold.getPricingConfig() + const treasury = await system.treasury.getAddress() + const feeToken = await usdcToken.getAddress() + const treasuryBefore = await interfold.pendingTreasuryClaim(treasury, feeToken) + const ownerAddress = await owner.getAddress() + const protocolAmount = (escrow * pricing.protocolShareBps) / 10_000n + const plaintext = readFileSync(path.join(fixtureDirectory, 'plaintext.bin')) + const completed = await (await interfold.publishPlaintextOutput(e3Id, plaintext, '0x01')).wait() + expect(completed!.status).to.equal(1) + expect(await interfold.getE3Stage(e3Id)).to.equal(5n) + expect((await interfold.getE3(e3Id)).plaintextOutput).to.equal(ethers.hexlify(plaintext)) + expect(await interfold.e3Payments(e3Id)).to.equal(0n) + expect(await interfold.pendingReward(e3Id, ownerAddress)).to.equal(escrow - protocolAmount) + expect(await interfold.pendingTreasuryClaim(treasury, feeToken)).to.equal(treasuryBefore + protocolAmount) + const beforeClaim = await usdcToken.balanceOf(ownerAddress) + await (await interfold.claimReward(e3Id)).wait() + expect((await usdcToken.balanceOf(ownerAddress)) - beforeClaim).to.equal(escrow - protocolAmount) + await waitFor('CRISP result indexing', async () => { + const response = await post('/state/result', { round_id: e3Id.toString() }) + if (!response.ok) return false + const result = await response.json() + return JSON.stringify(result.tally) === JSON.stringify(fixture.expected_tally.map(String)) + }) + save('complete', { + changed_proof_rejected: true, + settlement_verified: true, + expected_tally: fixture.expected_tally, + indexed_tally: fixture.expected_tally, + plaintext_publication_tx: completed!.hash, + threshold_decryption_proof_generated: false, + native_tally_checked: true, + }) + } catch (error) { + save('failed', { error: String(error) }) + throw error + } finally { + if (server && server.exitCode === null) { + server.kill('SIGTERM') + await Promise.race([new Promise((resolve) => server!.once('exit', resolve)), delay(10_000)]) + if (server.exitCode === null) server.kill('SIGKILL') + } + log.end() + } + }) +}) diff --git a/examples/CRISP/packages/crisp-contracts/tests/utils.ts b/examples/CRISP/packages/crisp-contracts/tests/utils.ts index 9331f2dc42..752cc59f1f 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/utils.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/utils.ts @@ -7,7 +7,7 @@ import { network } from 'hardhat' import type { HardhatEthers } from '@nomicfoundation/hardhat-ethers/types' import { zeroHash } from 'viem' -import { CRISPProgram, HonkVerifier, MockInterfold, MockRISC0Verifier, PoseidonT3 } from '../types' +import { CRISPProgram, HonkVerifier, MockInterfold, MockComputeReceiptVerifier, PoseidonT3 } from '../types' import { verifierNames } from '../scripts/verifiers' // Non-zero address used in the tests. @@ -140,10 +140,10 @@ export async function deployMockInterfold() { return contract as unknown as MockInterfold } -export async function deployMockRISC0Verifier() { - const contract = await deployContract('MockRISC0Verifier') +export async function deployMockComputeReceiptVerifier() { + const contract = await deployContract('MockComputeReceiptVerifier') - return contract as unknown as MockRISC0Verifier + return contract as unknown as MockComputeReceiptVerifier } /** @@ -200,7 +200,7 @@ export async function deployCRISPProgram( honkVerifier?: HonkVerifier onchainHonkVerifier?: HonkVerifier poseidonT3?: PoseidonT3 - risc0Verifier?: MockRISC0Verifier + computeVerifier?: MockComputeReceiptVerifier bindInterfold?: boolean availabilityFinalizationWindow?: number inputAvailabilitySigner?: string @@ -213,7 +213,7 @@ export async function deployCRISPProgram( // must pass the real one. const onchainHonkVerifier = contracts.onchainHonkVerifier || honkVerifier const mockInterfold = contracts.mockInterfold || (await deployMockInterfold()) - const risc0Verifier = contracts.risc0Verifier ? await contracts.risc0Verifier.getAddress() : nonZeroAddress + const computeVerifier = contracts.computeVerifier ? await contracts.computeVerifier.getAddress() : nonZeroAddress const dataAvailabilityVerifier = await deployContract('MockCrispDataAvailabilityVerifier') const programFactory = await ethers.getContractFactory('CRISPProgram', { @@ -225,7 +225,7 @@ export async function deployCRISPProgram( const program = await programFactory.deploy( await owner.getAddress(), - risc0Verifier, + computeVerifier, await honkVerifier.getAddress(), await onchainHonkVerifier.getAddress(), await dataAvailabilityVerifier.getAddress(), diff --git a/examples/CRISP/program/Cargo.toml b/examples/CRISP/program/Cargo.toml index 4fd21db997..4adbc4b9ff 100644 --- a/examples/CRISP/program/Cargo.toml +++ b/examples/CRISP/program/Cargo.toml @@ -3,6 +3,9 @@ name = "e3-user-program" version = { workspace = true } edition = { workspace = true } +[features] +openvm-hashes = ["e3-compute-provider/openvm-hashes", "dep:openvm-sha2"] + [dependencies] fhe = { workspace = true } fhe-traits = { workspace = true } @@ -10,8 +13,10 @@ e3-compute-provider = { workspace = true } sha2 = "=0.10.9" sha3 = "=0.10.8" e3-fhe-params = { workspace = true } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } [dev-dependencies] +anyhow.workspace = true hex = "=0.4.3" num-bigint = "0.5.1" serde_json = "=1.0.145" diff --git a/examples/CRISP/program/README.md b/examples/CRISP/program/README.md index 1024c93f8b..9dccb04c3b 100644 --- a/examples/CRISP/program/README.md +++ b/examples/CRISP/program/README.md @@ -1,86 +1,47 @@ -# CRISP Program +# CRISP program -The program module runs the FHE computation at the heart of CRISP: it aggregates encrypted votes, -produces a Risc0 ZK proof of correct execution, and submits the result back to the on-chain CRISP -contract via the coordination server. +The program implements CRISP's FHE processor and input policy. The OpenVM guest proves their +execution. The native host uses the same source to derive the ciphertext and expected journal. -## Architecture +CRISP does not sum every published entry. Its input policy validates commitments and follows each +slot's parent chain. Only the current valid head contributes to the encrypted tally. Every published +entry remains bound into the reconstructed input root. -```mermaid -graph TD - subgraph frontend["FRONTEND"] - client - end - subgraph ec2_1["BACKEND"] - server["server"] --> db - db[(DB)] +The proof binds the chain, Interfold address, full E3 ID, encryption scheme, committee key +commitment, ciphertext hash, SAFE commitment, parameter hash, and input root. - server --HTTP--> program - end - subgraph thirdparty["3rd PARTY"] - boundless - end - client --"HTTP"--> server - program ---> boundless +## Live compute flow - boundless["boundless (risc0)"] +The CRISP server sends the indexed inputs to the program server after the input deadline. The OpenVM +worker returns a verified proof. The program server delivers the ciphertext, commitment, and proof +envelope by HTTP callback. - server --"publishInput()"--> evm - subgraph evm["EVM"] - esol1["Interfold Contracts"] - csol1["CRISP Contracts"] - end - server -. "WebSocket listener" .-> evm -``` - -## What it computes - -CRISP uses BFV fully homomorphic encryption to tally votes. The Secure Process adds ciphertexts and -does not decrypt any input. A threshold committee decrypts only the combined result: - -1. The server collects BFV-encrypted vote ciphertexts from participants. -2. The program homomorphically adds all ciphertexts together to produce an encrypted tally. -3. A Risc0 guest program proves the aggregation was performed correctly. -4. The proof and ciphertext output are submitted on-chain; the Interfold ciphernode committee then - threshold-decrypts the result. - -## E3 Program Entry Points +CRISP validates the callback, obtains the output's availability receipt, and publishes the output +reference. Both the protocol and application verifier must pass before the E3 reaches +`CiphertextReady`. Threshold decryption follows separately. -The CRISP Solidity contract implements the three `IE3Program` entry points. Interfold calls two of -them. Data providers call `publishInput` on the program directly. +## Build and run -| Function | Called by | When called | What it does | -| --------------- | -------------------- | ------------------------------ | ---------------------------------------------------------------------------------------- | -| `validate` | Interfold | On E3 request | Validates request parameters, including the input window | -| `publishInput` | Voter or relay | Before the commitment cutoff | Verifies the Noir proof and availability-service signature, then reserves the input leaf | -| `finalizeInput` | Availability service | After VectorX proves inclusion | Verifies availability of the committed ciphertext hash | -| `verify` | Interfold | On output publication | Verifies the Risc0 proof and that the ciphertext output is correct | +Follow [the OpenVM instructions](../../../crates/support/openvm/README.md). Configure +`program.openvm` with the repository, worker, and worker-configuration paths. -## Proof Generation +From `examples/CRISP`, run: -Proof generation is delegated to [Boundless](https://boundless.network) (a Risc0 proving service): - -- **Development / local:** The program can run the Risc0 guest directly (no Boundless needed). -- **Production:** Set the `BOUNDLESS_RPC_URL` and `BOUNDLESS_PRIVATE_KEY` environment variables to - submit jobs to the Boundless network. See [Boundless configuration](../Readme.md#configuration) in - the CRISP root README. +```sh +pnpm dev:program +``` -## Environment Variables +The program server defaults to port 13151. The script uses the configured OpenVM backend. It does +not force unproved execution. -| Variable | Required | Description | -| ----------------------- | ---------- | ------------------------------------------------------------- | -| `RISC0_DEV_MODE` | Dev only | Set to `1` to skip real proof generation (fast local testing) | -| `BOUNDLESS_RPC_URL` | Production | RPC endpoint for Boundless proof submission | -| `BOUNDLESS_PRIVATE_KEY` | Production | Private key for paying Boundless proving fees | -| `PINATA_JWT` | Production | JWT for uploading the compiled guest binary to IPFS | -| `PROGRAM_URL` | Production | IPFS URL of the uploaded guest binary | +## Fresh test inputs -## Running locally +From the repository root: -```bash -# From the CRISP root -pnpm dev:program +```sh +pnpm openvm fixture ``` -This starts the program HTTP server (default port 3001). The coordination server calls it when a new -E3 computation request arrives. +The fixture generator creates fresh secure-8192 test ballots and checks the native aggregate and +tally. It does not produce ballot, DKG, or threshold-decryption proofs. Keep its output under +`target/` or outside the repository. diff --git a/examples/CRISP/program/examples/openvm_fixture.rs b/examples/CRISP/program/examples/openvm_fixture.rs new file mode 100644 index 0000000000..f2516d8c07 --- /dev/null +++ b/examples/CRISP/program/examples/openvm_fixture.rs @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +//! Generate fresh encrypted test ballots. This tool does not produce ballot or committee proofs. + +use anyhow::{ensure, Context, Result}; +use e3_bfv_client::client::{compute_ct_commitment_with_params, compute_pk_commitment}; +use e3_compute_provider::{ComputeInput, FHEInputs, PublishedData}; +use e3_fhe_params::{build_pair_for_preset, encode_bfv_params, BfvPreset}; +use fhe::bfv::{Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; +use fhe_traits::{ + DeserializeParametrized, FheDecoder, FheDecrypter, FheEncoder, FheEncrypter, Serialize, +}; +use serde_json::json; +use sha3::{Digest, Keccak256}; +use std::{fs, path::PathBuf}; + +fn main() -> Result<()> { + let mut args = std::env::args().skip(1); + let count: usize = args.next().context("Expected a vote count")?.parse()?; + let output = PathBuf::from(args.next().context("Expected a new output directory")?); + ensure!(args.next().is_none(), "Unexpected arguments"); + ensure!( + (1..=1024).contains(&count), + "Vote count must be between 1 and 1024" + ); + let (params, _) = build_pair_for_preset(BfvPreset::SecureThreshold8192)?; + let mut rng = rand::rng(); + let key = SecretKey::random(¶ms, &mut rng); + let public_key = PublicKey::new(&key, &mut rng); + let public_key_bytes = public_key.to_bytes(); + let public_key_commitment = compute_pk_commitment( + public_key_bytes.clone(), + params.degree(), + params.plaintext(), + params.moduli().to_vec(), + )?; + if let Some(parent) = output.parent() { + fs::create_dir_all(parent)?; + } + fs::create_dir(&output).context("The fixture directory must not already exist")?; + fs::create_dir(output.join("inputs"))?; + let mut ciphertexts = Vec::with_capacity(count); + let mut published = Vec::with_capacity(count); + let mut entries = Vec::with_capacity(count); + let mut expected_tally = [0u64; 2]; + for index in 0..count { + let weight = (index % 3 + 1) as u64; + let option = index % 2; + let mut coefficients = vec![0u64; params.degree()]; + for bit in 0..50 { + coefficients[option * 50 + bit] = (weight >> (49 - bit)) & 1; + } + let plaintext = Plaintext::try_encode(&coefficients, Encoding::poly(), ¶ms)?; + let ciphertext = public_key.try_encrypt(&plaintext, &mut rng)?.to_bytes(); + let commitment = compute_ct_commitment_with_params(&ciphertext, ¶ms)?; + let mut metadata = vec![0u8; 25]; + metadata[12..20].copy_from_slice(&(index as u64 + 1).to_be_bytes()); + entries.push(json!({ + "index": index, + "file": format!("inputs/{index}.bin"), + "content_hash": format!("0x{}", hex::encode(Keccak256::digest(&ciphertext))), + "commitment": format!("0x{}", hex::encode(commitment)), + "slot": format!("0x{}", hex::encode(&metadata[..20])), + "parent_index_plus_one": 0, + })); + fs::write(output.join(format!("inputs/{index}.bin")), &ciphertext)?; + ciphertexts.push((ciphertext, index as u64)); + published.push(PublishedData { + commitment: Some(commitment), + metadata, + }); + expected_tally[option] += weight; + } + let params_bytes = encode_bfv_params(¶ms); + let input = ComputeInput { + fhe_inputs: FHEInputs { + ciphertexts, + params: params_bytes.clone(), + }, + published, + }; + let (result, ciphertext) = input + .run(e3_user_program::fhe_processor, e3_user_program::policy()) + .map_err(|error| anyhow::anyhow!("{error}"))?; + let decrypted = key.try_decrypt(&Ciphertext::from_bytes(&ciphertext, ¶ms)?)?; + let coefficients: Vec = Vec::try_decode(&decrypted, Encoding::poly())?; + let decode = |offset: usize| { + coefficients[offset..offset + 50] + .iter() + .fold(0u64, |value, bit| value * 2 + bit) + }; + ensure!( + [decode(0), decode(50)] == expected_tally, + "Native tally differs from the ballots" + ); + ensure!( + coefficients[100..] + .iter() + .all(|coefficient| *coefficient == 0), + "Unexpected coefficients outside the tally" + ); + fs::write(output.join("public-key.bin"), &public_key_bytes)?; + fs::write(output.join("ciphertext.bin"), &ciphertext)?; + fs::write( + output.join("plaintext.bin"), + coefficients + .iter() + .flat_map(|value| value.to_le_bytes()) + .collect::>(), + )?; + let context = json!({ + "preset": "secure-8192", "param_set": 1, "inputs": entries, + "params": format!("0x{}", hex::encode(params_bytes)), + "public_key_commitment": format!("0x{}", hex::encode(public_key_commitment)), + "input_root": format!("0x{}", hex::encode(result.merkle_root)), + "ciphertext_hash": format!("0x{}", hex::encode(result.ciphertext_hash)), + "ciphertext_commitment": format!("0x{}", hex::encode(result.ciphertext_commitment)), + "expected_tally": expected_tally, "native_tally_checked": true, + "ballot_proofs_generated": false, "threshold_decryption_proof_generated": false, + }); + fs::write( + output.join("fixture.json"), + serde_json::to_vec_pretty(&context)?, + )?; + println!( + "Generated {count} fresh secure-8192 test ballots in {}", + output.display() + ); + Ok(()) +} diff --git a/examples/CRISP/program/src/lib.rs b/examples/CRISP/program/src/lib.rs index b3c6f30258..58a8c1c8dc 100644 --- a/examples/CRISP/program/src/lib.rs +++ b/examples/CRISP/program/src/lib.rs @@ -33,10 +33,15 @@ pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { /// Both are specific to this program and its contract. They live here, beside the `CRISPProgram` /// they must agree with, rather than in `e3-compute-provider`, which every E3 program shares. pub mod policy { - use e3_compute_provider::policy::{leaf_from_digest, PublishedInput}; + use e3_compute_provider::hashing::keccak256; + use e3_compute_provider::policy::{PublishedInput, leaf_from_digest}; use e3_compute_provider::{ComputeError, InputPolicy}; - use sha2::{Digest, Sha256}; - use sha3::Keccak256; + #[cfg(feature = "openvm-hashes")] + use openvm_sha2::Sha256; + #[cfg(not(all(feature = "openvm-hashes", target_os = "zkvm")))] + use sha2::Digest; + #[cfg(not(feature = "openvm-hashes"))] + use sha2::Sha256; use std::collections::BTreeMap; /// The metadata `CRISPProgram` publishes with each input: 20-byte slot, then a 5-byte parent. @@ -95,7 +100,7 @@ pub mod policy { metadata_of(input)?; let mut outer = Sha256::new(); - outer.update(Keccak256::digest(input.ciphertext)); + outer.update(&keccak256(input.ciphertext)); outer.update(commitment); outer.update(input.metadata); Ok(leaf_from_digest(&outer.finalize())) diff --git a/examples/CRISP/program/tests/secure_process.rs b/examples/CRISP/program/tests/secure_process.rs index a914669f45..b5bc49a7c4 100644 --- a/examples/CRISP/program/tests/secure_process.rs +++ b/examples/CRISP/program/tests/secure_process.rs @@ -4,7 +4,7 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -//! Runs the CRISP Secure Process natively, outside the RISC Zero zkVM. +//! Runs the CRISP Secure Process natively, outside the OpenVM guest. //! //! The guest is one line — `input.input.process(fhe_processor, crisp())` — so calling that here //! exercises the same code the zkVM runs, with the real CRISP processor and the real CRISP policy. diff --git a/examples/CRISP/scripts/dev_program.sh b/examples/CRISP/scripts/dev_program.sh index 091a230d85..abd2b16bd3 100755 --- a/examples/CRISP/scripts/dev_program.sh +++ b/examples/CRISP/scripts/dev_program.sh @@ -8,4 +8,4 @@ source "${SCRIPT_DIR}/lib/dev_config.sh" load_crisp_dev_config -interfold program start --dev true +interfold program start diff --git a/examples/CRISP/server/.env.example b/examples/CRISP/server/.env.example index b089150d2e..64c15ea887 100644 --- a/examples/CRISP/server/.env.example +++ b/examples/CRISP/server/.env.example @@ -2,6 +2,8 @@ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 # Remote cron targets must use HTTPS. Use 127.0.0.1 (not 0.0.0.0) for local development. INTERFOLD_SERVER_URL=http://127.0.0.1:4000 +# Listener address. Use loopback for a server that does not need remote clients. +CRISP_BIND_ADDR=127.0.0.1:4000 HTTP_RPC_URL=http://127.0.0.1:8545 PROGRAM_SERVER_URL=http://127.0.0.1:13151 WS_RPC_URL=ws://127.0.0.1:8545 @@ -76,7 +78,7 @@ RELAY_MAX_INPUTS_PER_ROUND= RELAY_MIN_BALANCE_ETH= # E3 Compute Provider Config -E3_COMPUTE_PROVIDER_NAME="RISC0" +E3_COMPUTE_PROVIDER_NAME="OpenVM" E3_COMPUTE_PROVIDER_PARALLEL=false E3_COMPUTE_PROVIDER_BATCH_SIZE=4 # Must be a power of 2 diff --git a/examples/CRISP/server/Dockerfile b/examples/CRISP/server/Dockerfile index 1ecb152db1..dbbeba69a6 100644 --- a/examples/CRISP/server/Dockerfile +++ b/examples/CRISP/server/Dockerfile @@ -16,8 +16,6 @@ RUN wget https://github.com/argotorg/solidity/releases/download/v0.8.27/solc-sta && mv solc-static-linux /usr/local/bin/solc \ && solc --version -RUN curl -sSfL https://risczero.com/install | bash - RUN cargo install --locked cargo-chef ################################################# diff --git a/examples/CRISP/server/Readme.md b/examples/CRISP/server/Readme.md index 3726281521..b07a3137ab 100644 --- a/examples/CRISP/server/Readme.md +++ b/examples/CRISP/server/Readme.md @@ -8,7 +8,7 @@ Protocol, which handles E3 (Encrypted Execution Environment) rounds and voting p - Create and manage voting rounds (E3 rounds) - Secure vote casting using FHE - Real-time blockchain event handling and processing -- RISC Zero compute provider for proof generation +- OpenVM program-service integration and verified HTTP callbacks - CLI for manual interaction ## Prerequisites diff --git a/examples/CRISP/server/src/server/data_availability.rs b/examples/CRISP/server/src/server/data_availability.rs index 8398bdca17..50e07fd46f 100644 --- a/examples/CRISP/server/src/server/data_availability.rs +++ b/examples/CRISP/server/src/server/data_availability.rs @@ -1113,7 +1113,7 @@ impl AvailabilityService { e3_data_availability::validate_object_bytes(&ciphertext)?; let hash = keccak256(&ciphertext); // The output statement is the E3, exact ciphertext hash, and ciphertext commitment. The - // RISC Zero seal proves that statement but is not its identity: another valid seal must be + // OpenVM seal proves that statement but is not its identity: another valid seal must be // an idempotent retry, not another paid Avail publication. let id = self.job_id(b"output", e3_id, hash, &ciphertext_commitment)?; if let Some(job) = self.load(&id)? { diff --git a/examples/CRISP/server/src/server/indexer.rs b/examples/CRISP/server/src/server/indexer.rs index e6a7266649..f2f6134644 100644 --- a/examples/CRISP/server/src/server/indexer.rs +++ b/examples/CRISP/server/src/server/indexer.rs @@ -742,7 +742,7 @@ async fn wait_for_indexed_inputs( // Equality is required. Fewer entries means that an accepted input is missing. More // entries means that the local index contains data the contract did not accept. Either - // case would make the RISC Zero input root differ from the contract's root. + // case would make the OpenVM input root differ from the contract's root. if indexed == published { return Ok(IndexedInputs::Complete(snapshot)); } @@ -951,7 +951,7 @@ async fn handle_e3_input_deadline_expiration( .await?; if pending != 0 { // The input root already includes these reserved leaves, but Ethereum has not verified - // their Avail receipts. Starting RISC Zero now would waste the proof: CRISPProgram.verify + // their Avail receipts. Starting OpenVM now would waste the proof: CRISPProgram.verify // refuses every output until this reaches zero. InputPublished recovery wakes this handler // again as each delayed VectorX proof lands. return Err(eyre::eyre!( diff --git a/examples/CRISP/server/src/server/mod.rs b/examples/CRISP/server/src/server/mod.rs index fffa2085d9..02ae5ad789 100644 --- a/examples/CRISP/server/src/server/mod.rs +++ b/examples/CRISP/server/src/server/mod.rs @@ -11,6 +11,7 @@ mod database; mod indexer; mod log_repo; mod models; +mod payloads; mod program_server_request; mod rate_limit; mod read_cache; @@ -35,7 +36,9 @@ use tokio::sync::RwLock; use crate::config::CONFIG; use crate::logger::init_logger; -#[actix_web::main] +// Keep RPC transports responsive while an indexer task validates encrypted inputs or serializes +// a large round record. A single-thread runtime can miss WebSocket heartbeats during that work. +#[tokio::main] pub async fn start() -> Result<(), Box> { init_logger(); @@ -117,7 +120,7 @@ pub async fn start() -> Result<(), Box> { } }); - let bind_addr = "0.0.0.0:4000"; + let bind_addr = std::env::var("CRISP_BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:4000".to_owned()); let db_clone = db.clone(); let availability_clone = availability.clone(); // Built once, outside the factory closure: the closure runs per worker, and a per-worker @@ -145,7 +148,7 @@ pub async fn start() -> Result<(), Box> { .app_data(chain_rate_limiter.clone()) .configure(routes::setup_routes) }) - .bind(bind_addr)?; + .bind(&bind_addr)?; println!("'crisp-server' listening on http://{}", bind_addr); diff --git a/examples/CRISP/server/src/server/payloads.rs b/examples/CRISP/server/src/server/payloads.rs new file mode 100644 index 0000000000..51e7a6f07c --- /dev/null +++ b/examples/CRISP/server/src/server/payloads.rs @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +use actix_web::web; + +// Allow a maximum-size hex-encoded DA object plus its proof and envelope. +// Retain Actix's smaller default JSON limit on ordinary read endpoints. +const ENCRYPTED_JSON_LIMIT: usize = 4 * e3_data_availability::MAX_OBJECT_BYTES; + +pub fn encrypted_json() -> web::JsonConfig { + web::JsonConfig::default().limit(ENCRYPTED_JSON_LIMIT) +} + +#[cfg(test)] +mod tests { + use super::*; + use actix_web::{http::StatusCode, test, App, HttpResponse}; + + async fn accept(_: web::Json) -> HttpResponse { + HttpResponse::Ok().finish() + } + + #[actix_web::test] + async fn encrypted_payload_limit_is_bounded_and_route_local() { + let app = test::init_service( + App::new() + .service( + web::resource("/encrypted") + .app_data(encrypted_json()) + .route(web::post().to(accept)), + ) + .route("/read", web::post().to(accept)), + ) + .await; + let payload = + serde_json::json!({"ciphertext": "ab".repeat(e3_data_availability::MAX_OBJECT_BYTES)}); + let accepted = test::TestRequest::post() + .uri("/encrypted") + .set_json(&payload) + .to_request(); + assert_eq!( + test::call_service(&app, accepted).await.status(), + StatusCode::OK + ); + let ordinary = test::TestRequest::post() + .uri("/read") + .set_json(&payload) + .to_request(); + assert_eq!( + test::call_service(&app, ordinary).await.status(), + StatusCode::PAYLOAD_TOO_LARGE + ); + let oversized = test::TestRequest::post() + .uri("/encrypted") + .set_json(serde_json::json!({"ciphertext": "a".repeat(ENCRYPTED_JSON_LIMIT)})) + .to_request(); + assert_eq!( + test::call_service(&app, oversized).await.status(), + StatusCode::PAYLOAD_TOO_LARGE + ); + } +} diff --git a/examples/CRISP/server/src/server/routes/state.rs b/examples/CRISP/server/src/server/routes/state.rs index 366f9df6be..951efd0e8b 100644 --- a/examples/CRISP/server/src/server/routes/state.rs +++ b/examples/CRISP/server/src/server/routes/state.rs @@ -32,7 +32,11 @@ pub fn setup_routes(config: &mut web::ServiceConfig) { .route("/lite", web::post().to(get_round_state_lite)) // The handler verifies the compute proof on Ethereum before it creates an Avail job. // Valid retries are idempotent, so this endpoint needs no separate caller identity. - .route("/add-result", web::post().to(handle_program_server_result)) + .service( + web::resource("/add-result") + .app_data(crate::server::payloads::encrypted_json()) + .route(web::post().to(handle_program_server_result)), + ) // Get the token holders hashes for a given round .route("/token-holders", web::post().to(get_token_holders_hashes)) .route( diff --git a/examples/CRISP/server/src/server/routes/voting.rs b/examples/CRISP/server/src/server/routes/voting.rs index 72865d0c25..50e6b6a263 100644 --- a/examples/CRISP/server/src/server/routes/voting.rs +++ b/examples/CRISP/server/src/server/routes/voting.rs @@ -32,7 +32,11 @@ pub fn setup_routes(config: &mut web::ServiceConfig) { ); config.service( web::scope("/voting") - .route("/broadcast", web::post().to(broadcast_encrypted_vote)) + .service( + web::resource("/broadcast") + .app_data(crate::server::payloads::encrypted_json()) + .route(web::post().to(broadcast_encrypted_vote)), + ) .route( "/availability/{job_id}", web::get().to(get_availability_status), diff --git a/package.json b/package.json index 6266db1018..43ecbdb9a3 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "config:release": "cd packages/interfold-config && pnpm release", "react:release": "cd packages/interfold-react && pnpm release", "npm:release": "pnpm build && pnpm config:release && pnpm evm:release && pnpm wasm:release && pnpm sdk:release && pnpm react:release && pnpm mcp:release", + "openvm": "bash scripts/run-openvm.sh", "support:build": "cd crates/support && ./scripts/build.sh", "build": "pnpm compile", "fixtures:build": "cd crates/evm-helpers && ./scripts/build_fixtures.sh && cd ../indexer && ./scripts/build_fixtures.sh", diff --git a/packages/interfold-contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol b/packages/interfold-contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol new file mode 100644 index 0000000000..3c7d8b27e3 --- /dev/null +++ b/packages/interfold-contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity 0.8.28; + +/// @notice Verifies an OpenVM receipt against a configured application and journal digest. +interface IOpenVmReceiptVerifier { + function verify( + bytes calldata seal, + bytes32 imageId, + bytes32 journalDigest + ) external view; +} diff --git a/packages/interfold-contracts/contracts/lib/OpenVmComputeProof.sol b/packages/interfold-contracts/contracts/lib/OpenVmComputeProof.sol new file mode 100644 index 0000000000..707ba66a79 --- /dev/null +++ b/packages/interfold-contracts/contracts/lib/OpenVmComputeProof.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity 0.8.28; + +library OpenVmComputeProof { + struct Proof { + bytes seal; + bytes32 paramsHash; + bytes32 inputRoot; + } + + function decode(bytes memory encoded) internal pure returns (Proof memory) { + (bytes memory seal, bytes32 paramsHash, bytes32 inputRoot) = abi.decode( + encoded, + (bytes, bytes32, bytes32) + ); + return Proof(seal, paramsHash, inputRoot); + } + + /// @notice Encode the exact nine words whose SHA-256 digest the guest reveals. + function journal( + bytes32 chainId, + bytes32 verifyingContract, + bytes32 e3Id, + bytes32 encryptionSchemeId, + bytes32 committeePublicKey, + bytes32 ciphertextOutputHash, + bytes32 ciphertextCommitment, + bytes32 paramsHash, + bytes32 inputRoot + ) internal pure returns (bytes memory) { + return + abi.encode( + chainId, + verifyingContract, + e3Id, + encryptionSchemeId, + committeePublicKey, + ciphertextOutputHash, + ciphertextCommitment, + paramsHash, + inputRoot + ); + } +} diff --git a/packages/interfold-contracts/contracts/verifiers/OpenVmReceiptVerifier.sol b/packages/interfold-contracts/contracts/verifiers/OpenVmReceiptVerifier.sol new file mode 100644 index 0000000000..9ca0e51c78 --- /dev/null +++ b/packages/interfold-contracts/contracts/verifiers/OpenVmReceiptVerifier.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +pragma solidity 0.8.28; + +import { + IOpenVmReceiptVerifier +} from "../interfaces/IOpenVmReceiptVerifier.sol"; + +interface IOpenVmHalo2Verifier { + function verify( + bytes calldata publicValues, + bytes calldata proofData, + bytes32 appExeCommit, + bytes32 appVmCommit + ) external view; +} + +/// @notice Verifies the Halo2 proof and binds it to one OpenVM executable and VM. +contract OpenVmReceiptVerifier is IOpenVmReceiptVerifier { + uint256 private constant SCALAR_MODULUS = + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; + uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32; + bytes32 public constant IMAGE_DOMAIN = + keccak256("INTERFOLD_OPENVM_RECEIPT_V1"); + + IOpenVmHalo2Verifier public immutable verifier; + bytes32 public immutable appExeCommit; + bytes32 public immutable appVmCommit; + bytes32 public immutable imageId; + + error InvalidVerifier(); + error InvalidAppCommitment(); + error WrongImageId(); + error InvalidSealVersion(); + error InvalidSealEncoding(); + error InvalidProofDataLength(); + error JournalDigestMismatch(); + + constructor( + IOpenVmHalo2Verifier verifier_, + bytes32 appExeCommit_, + bytes32 appVmCommit_ + ) { + if (address(verifier_).code.length == 0) revert InvalidVerifier(); + if ( + appExeCommit_ == bytes32(0) || + appVmCommit_ == bytes32(0) || + uint256(appExeCommit_) >= SCALAR_MODULUS || + uint256(appVmCommit_) >= SCALAR_MODULUS + ) revert InvalidAppCommitment(); + verifier = verifier_; + appExeCommit = appExeCommit_; + appVmCommit = appVmCommit_; + imageId = keccak256( + abi.encode( + IMAGE_DOMAIN, + address(verifier_), + appExeCommit_, + appVmCommit_ + ) + ); + } + + /// @notice Check the caller's journal digest and verify the corresponding OpenVM public values. + /// @dev The seal contains a version, Halo2 proof data, and all nine journal words. + function verify( + bytes calldata seal, + bytes32 expectedImageId, + bytes32 expectedJournalDigest + ) external view { + if (expectedImageId != imageId) revert WrongImageId(); + (uint8 version, bytes memory proofData, bytes32[9] memory words) = abi + .decode(seal, (uint8, bytes, bytes32[9])); + if (version != 1) revert InvalidSealVersion(); + if (keccak256(seal) != keccak256(abi.encode(version, proofData, words))) + revert InvalidSealEncoding(); + if (proofData.length != PROOF_DATA_LENGTH) + revert InvalidProofDataLength(); + + bytes memory callerJournal = abi.encode(words); + if (sha256(callerJournal) != expectedJournalDigest) + revert JournalDigestMismatch(); + + verifier.verify( + abi.encodePacked(expectedJournalDigest), + proofData, + appExeCommit, + appVmCommit + ); + } +} diff --git a/packages/interfold-contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol b/packages/interfold-contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol new file mode 100644 index 0000000000..bf5901e475 --- /dev/null +++ b/packages/interfold-contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +pragma solidity 0.8.28; + +import { ICiphertextVerifier } from "../../interfaces/ICiphertextVerifier.sol"; +import { OpenVmComputeProof } from "../../lib/OpenVmComputeProof.sol"; + +import { + IOpenVmReceiptVerifier +} from "../../interfaces/IOpenVmReceiptVerifier.sol"; + +/** + * @title OpenVmBfvCiphertextVerifier + * @notice Verifies the protocol fields committed by the BFV compute guest. + */ +contract OpenVmBfvCiphertextVerifier is ICiphertextVerifier { + error InvalidImageId(); + error InvalidVerifier(); + + IOpenVmReceiptVerifier public immutable openVmVerifier; + bytes32 public immutable imageId; + + constructor(IOpenVmReceiptVerifier verifier, bytes32 guestImageId) { + if (address(verifier).code.length == 0) revert InvalidVerifier(); + if (guestImageId == bytes32(0)) revert InvalidImageId(); + openVmVerifier = verifier; + imageId = guestImageId; + } + + /// @inheritdoc ICiphertextVerifier + function verify( + uint256 e3Id, + bytes32 encryptionSchemeId, + bytes32 paramsHash, + bytes32 committeePublicKey, + bytes32 ciphertextOutputHash, + bytes32 ciphertextCommitment, + bytes calldata encodedProof + ) external view returns (bool) { + OpenVmComputeProof.Proof memory proof = OpenVmComputeProof.decode( + encodedProof + ); + if (proof.paramsHash != paramsHash) return false; + openVmVerifier.verify( + proof.seal, + imageId, + _journalDigest( + e3Id, + encryptionSchemeId, + paramsHash, + committeePublicKey, + ciphertextOutputHash, + ciphertextCommitment, + proof.inputRoot + ) + ); + return true; + } + + function _journalDigest( + uint256 e3Id, + bytes32 encryptionSchemeId, + bytes32 paramsHash, + bytes32 committeePublicKey, + bytes32 ciphertextOutputHash, + bytes32 ciphertextCommitment, + bytes32 inputRoot + ) private view returns (bytes32) { + return + sha256( + OpenVmComputeProof.journal( + bytes32(block.chainid), + bytes32(uint256(uint160(msg.sender))), + bytes32(e3Id), + encryptionSchemeId, + committeePublicKey, + ciphertextOutputHash, + ciphertextCommitment, + paramsHash, + inputRoot + ) + ); + } +} diff --git a/packages/interfold-contracts/scripts/index.ts b/packages/interfold-contracts/scripts/index.ts index cade25b3ee..bbfac8b86a 100644 --- a/packages/interfold-contracts/scripts/index.ts +++ b/packages/interfold-contracts/scripts/index.ts @@ -22,3 +22,4 @@ export * from "./deployAndSave/mockProgram"; export * from "./deployAndSave/verifiers"; export * from "./verify"; export * from "./dataAvailability"; +export * from "./openVm"; diff --git a/packages/interfold-contracts/scripts/openVm.ts b/packages/interfold-contracts/scripts/openVm.ts new file mode 100644 index 0000000000..9101063b97 --- /dev/null +++ b/packages/interfold-contracts/scripts/openVm.ts @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +import type { HardhatEthers } from "@nomicfoundation/hardhat-ethers/types"; +import { createHash } from "node:crypto"; +import { readFileSync, statSync } from "node:fs"; + +/** Deploy a receipt binding from explicit application commitments and a checked Halo2 verifier. */ +export async function deployOpenVmReceiptVerifier( + ethers: HardhatEthers, + environment: Record = process.env, +) { + const required = (name: string): string => { + const value = environment[name]; + if (!value) + throw new Error(`Set ${name}; OpenVM has no default compute verifier`); + return value; + }; + const appExeCommit = required("OPENVM_APP_EXE_COMMIT"); + const appVmCommit = required("OPENVM_APP_VM_COMMIT"); + const scalarModulus = + 21888242871839275222246405745257275088548364400416034343698204186575808495617n; + for (const value of [appExeCommit, appVmCommit]) { + if ( + !/^0x[0-9a-fA-F]{64}$/.test(value) || + BigInt(value) === 0n || + BigInt(value) >= scalarModulus + ) { + throw new Error( + "OpenVM application commitments must be nonzero canonical 32-byte scalars", + ); + } + } + const artifactPath = environment.OPENVM_VERIFIER_ARTIFACT; + if (artifactPath && environment.OPENVM_HALO2_VERIFIER) { + throw new Error( + "Configure an OpenVM verifier artifact or an existing verifier address, not both", + ); + } + let halo2Verifier: string; + if (artifactPath) { + const checksum = required("OPENVM_VERIFIER_SHA256"); + if (!/^[0-9a-f]{64}$/.test(checksum)) + throw new Error( + "The OpenVM artifact checksum must be a lowercase SHA-256 digest", + ); + if (statSync(artifactPath).size > 256 * 1024) + throw new Error("The OpenVM verifier artifact exceeds the byte limit"); + const bytes = readFileSync(artifactPath); + if (createHash("sha256").update(bytes).digest("hex") !== checksum) + throw new Error("The OpenVM verifier artifact checksum differs"); + const artifact = JSON.parse(bytes.toString("utf8")); + if ( + typeof artifact.bytecode !== "string" || + !/^(?:0x)?(?:[0-9a-fA-F]{2})+$/.test(artifact.bytecode) + ) { + throw new Error( + "The OpenVM verifier artifact must contain hexadecimal creation bytecode", + ); + } + const [owner] = await ethers.getSigners(); + const halo2 = await new ethers.ContractFactory( + ["function verify(bytes,bytes,bytes32,bytes32) view"], + `0x${artifact.bytecode.replace(/^0x/, "")}`, + owner, + ).deploy(); + await halo2.waitForDeployment(); + halo2Verifier = await halo2.getAddress(); + } else { + halo2Verifier = ethers.getAddress(required("OPENVM_HALO2_VERIFIER")); + const code = await ethers.provider.getCode(halo2Verifier); + if ( + code === "0x" || + ethers.keccak256(code).toLowerCase() !== + required("OPENVM_HALO2_RUNTIME_CODE_HASH").toLowerCase() + ) { + throw new Error( + "The OpenVM verifier runtime code differs from the configured hash", + ); + } + } + const code = await ethers.provider.getCode(halo2Verifier); + if (code === "0x") + throw new Error("The OpenVM Halo2 verifier has no deployed code"); + const receipt = await ethers.deployContract("OpenVmReceiptVerifier", [ + halo2Verifier, + appExeCommit, + appVmCommit, + ]); + await receipt.waitForDeployment(); + return { + receipt, + halo2Verifier, + halo2RuntimeCodeHash: ethers.keccak256(code), + appExeCommit, + appVmCommit, + }; +} diff --git a/packages/interfold-contracts/scripts/protocol/types.ts b/packages/interfold-contracts/scripts/protocol/types.ts index 62acd452de..1efec96d42 100644 --- a/packages/interfold-contracts/scripts/protocol/types.ts +++ b/packages/interfold-contracts/scripts/protocol/types.ts @@ -119,7 +119,7 @@ export interface ProtocolConfigFile { pkVerifier?: string; dkgFoldAttestationVerifier?: string; /** - * The protocol ciphertext verifier for the BFV scheme, e.g. `Risc0BfvCiphertextVerifier`. + * The protocol ciphertext verifier for the BFV scheme, such as `OpenVmBfvCiphertextVerifier`. * * This is the contract that checks the compute receipt before an E3 reaches * `CiphertextReady`. Its `imageId` is immutable, so replacing it is a redeployment, not a diff --git a/packages/interfold-contracts/test/Deployment/OpenVm.spec.ts b/packages/interfold-contracts/test/Deployment/OpenVm.spec.ts new file mode 100644 index 0000000000..6d2add299b --- /dev/null +++ b/packages/interfold-contracts/test/Deployment/OpenVm.spec.ts @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +import { expect } from "chai"; +import { artifacts } from "hardhat"; +import { createHash } from "node:crypto"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; + +import { deployOpenVmReceiptVerifier } from "../../scripts/openVm"; +import { ethers } from "../fixtures/connection"; + +describe("OpenVM deployment configuration", function () { + const commitments = { + OPENVM_APP_EXE_COMMIT: ethers.zeroPadValue("0x01", 32), + OPENVM_APP_VM_COMMIT: ethers.zeroPadValue("0x02", 32), + }; + + it("requires explicit configuration and rejects noncanonical commitments", async function () { + await expect(deployOpenVmReceiptVerifier(ethers, {})).to.be.rejectedWith( + "OPENVM_APP_EXE_COMMIT", + ); + await expect( + deployOpenVmReceiptVerifier(ethers, commitments), + ).to.be.rejectedWith("OPENVM_HALO2_VERIFIER"); + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...commitments, + OPENVM_APP_VM_COMMIT: ethers.ZeroHash, + }), + ).to.be.rejectedWith("nonzero canonical"); + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...commitments, + OPENVM_APP_VM_COMMIT: `0x${"ff".repeat(32)}`, + }), + ).to.be.rejectedWith("nonzero canonical"); + }); + + it("requires deployed code and its exact runtime hash", async function () { + const [owner] = await ethers.getSigners(); + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...commitments, + OPENVM_HALO2_VERIFIER: owner.address, + OPENVM_HALO2_RUNTIME_CODE_HASH: ethers.ZeroHash, + }), + ).to.be.rejectedWith("runtime code differs"); + // This test checks deployment bindings only. The real-proof suite supplies the Halo2 artifact. + const target = await ethers.deployContract("MockCiphertextVerifier"); + const address = await target.getAddress(); + const codeHash = ethers.keccak256(await ethers.provider.getCode(address)); + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...commitments, + OPENVM_HALO2_VERIFIER: address, + OPENVM_HALO2_RUNTIME_CODE_HASH: ethers.ZeroHash, + }), + ).to.be.rejectedWith("runtime code differs"); + const { receipt } = await deployOpenVmReceiptVerifier(ethers, { + ...commitments, + OPENVM_HALO2_VERIFIER: address, + OPENVM_HALO2_RUNTIME_CODE_HASH: codeHash, + }); + expect(await receipt.verifier()).to.equal(address); + expect(await receipt.appExeCommit()).to.equal( + commitments.OPENVM_APP_EXE_COMMIT, + ); + }); + + it("checks artifact bytes and refuses conflicting deployment modes", async function () { + const directory = mkdtempSync( + path.join(tmpdir(), "interfold-openvm-deploy-"), + ); + try { + const artifact = await artifacts.readArtifact("MockCiphertextVerifier"); + const bytes = JSON.stringify({ bytecode: artifact.bytecode }); + const file = path.join(directory, "verifier.json"); + writeFileSync(file, bytes); + const config = { + ...commitments, + OPENVM_VERIFIER_ARTIFACT: file, + OPENVM_VERIFIER_SHA256: createHash("sha256") + .update(bytes) + .digest("hex"), + }; + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...config, + OPENVM_HALO2_VERIFIER: ethers.ZeroAddress, + }), + ).to.be.rejectedWith("not both"); + await expect( + deployOpenVmReceiptVerifier(ethers, { + ...config, + OPENVM_VERIFIER_SHA256: "0".repeat(64), + }), + ).to.be.rejectedWith("checksum differs"); + const { receipt, halo2Verifier } = await deployOpenVmReceiptVerifier( + ethers, + config, + ); + expect(await receipt.verifier()).to.equal(halo2Verifier); + expect(await ethers.provider.getCode(halo2Verifier)).not.to.equal("0x"); + } finally { + rmSync(directory, { recursive: true }); + } + }); +}); diff --git a/packages/interfold-contracts/test/fixtures/system.ts b/packages/interfold-contracts/test/fixtures/system.ts index 346f0ad336..a5488714bc 100644 --- a/packages/interfold-contracts/test/fixtures/system.ts +++ b/packages/interfold-contracts/test/fixtures/system.ts @@ -97,6 +97,8 @@ export type CommitteeThreshold = [number, [number, number]]; /** Options accepted by {@link deployInterfoldSystem}. All optional. */ export interface DeployInterfoldSystemOptions { + /** Isolate deployments when a fixture uses a persistent local HTTP node. */ + deploymentId?: string; /** Override the sortition submission window (seconds). */ submissionWindow?: number; /** Override `Interfold.maxDuration` (seconds). */ @@ -230,6 +232,11 @@ export interface InterfoldSystem { export async function deployInterfoldSystem( opts: DeployInterfoldSystemOptions = {}, ): Promise { + const deploy: typeof ignition.deploy = (module, options) => + ignition.deploy(module, { + ...options, + ...(opts.deploymentId ? { deploymentId: opts.deploymentId } : {}), + }); const submissionWindow = opts.submissionWindow ?? SORTITION_SUBMISSION_WINDOW; const maxDuration = opts.maxDuration ?? THIRTY_DAYS; const timeoutConfig = opts.timeoutConfig ?? DEFAULT_TIMEOUT_CONFIG; @@ -271,7 +278,7 @@ export async function deployInterfoldSystem( // ABI-compatible with MockUSDC for the operations the fixture/spec needs. usdcToken = blacklistToken as unknown as MockUSDC; } else { - const { mockUSDC } = await ignition.deploy(MockStableTokenModule, { + const { mockUSDC } = await deploy(MockStableTokenModule, { parameters: { MockUSDC: { initialSupply: 10_000_000 } }, }); usdcToken = MockUSDCFactory.connect(await mockUSDC.getAddress(), owner); @@ -280,25 +287,22 @@ export async function deployInterfoldSystem( // Deferred: InterfoldToken is deployed after BondingRegistry so the // immutable BONDING_REGISTRY reference can be set. See below. - const { interfoldTicketToken } = await ignition.deploy( - InterfoldTicketTokenModule, - { - parameters: { - InterfoldTicketToken: { - baseToken: await usdcToken.getAddress(), - registry: ADDRESS_ONE, - owner: ownerAddress, - }, + const { interfoldTicketToken } = await deploy(InterfoldTicketTokenModule, { + parameters: { + InterfoldTicketToken: { + baseToken: await usdcToken.getAddress(), + registry: ADDRESS_ONE, + owner: ownerAddress, }, }, - ); + }); const ticketToken = InterfoldTicketTokenFactory.connect( await interfoldTicketToken.getAddress(), owner, ); // ── Registry & Slashing ─────────────────────────────────────────────────── - const { slashingManager: _slashingManager } = await ignition.deploy( + const { slashingManager: _slashingManager } = await deploy( SlashingManagerModule, { parameters: { SlashingManager: { admin: ownerAddress } } }, ); @@ -307,17 +311,14 @@ export async function deployInterfoldSystem( owner, ); - const { cipherNodeRegistry } = await ignition.deploy( - CiphernodeRegistryModule, - { - parameters: { - CiphernodeRegistry: { - owner: ownerAddress, - submissionWindow, - }, + const { cipherNodeRegistry } = await deploy(CiphernodeRegistryModule, { + parameters: { + CiphernodeRegistry: { + owner: ownerAddress, + submissionWindow, }, }, - ); + }); const ciphernodeRegistryAddress = await cipherNodeRegistry.getAddress(); const ciphernodeRegistry = CiphernodeRegistryOwnableFactory.connect( ciphernodeRegistryAddress, @@ -330,7 +331,7 @@ export async function deployInterfoldSystem( let mockCiphernodeRegistry: MockCiphernodeRegistry | undefined; let effectiveRegistryAddress = ciphernodeRegistryAddress; if (opts.useMockCiphernodeRegistry) { - const { mockCiphernodeRegistry: _mockReg } = await ignition.deploy( + const { mockCiphernodeRegistry: _mockReg } = await deploy( MockCiphernodeRegistryModule, ); const mockRegAddress = await _mockReg.getAddress(); @@ -342,7 +343,7 @@ export async function deployInterfoldSystem( } // ── BondingRegistry (deployed before token; uses ADDRESS_ONE placeholder) ── - const { bondingRegistry: _bondingRegistry } = await ignition.deploy( + const { bondingRegistry: _bondingRegistry } = await deploy( BondingRegistryModule, { parameters: { @@ -376,7 +377,7 @@ export async function deployInterfoldSystem( const claimSource = ownerAddress; // owner as placeholder claim source const lockSunsetDelay = 4n * 365n * 24n * 60n * 60n + 30n * 24n * 60n * 60n; const noMoreLocks = ccaEnd + 45n * 24n * 60n * 60n + lockSunsetDelay; - const { interfoldToken } = await ignition.deploy(InterfoldTokenModule, { + const { interfoldToken } = await deploy(InterfoldTokenModule, { parameters: { InterfoldToken: { owner: ownerAddress, @@ -404,8 +405,7 @@ export async function deployInterfoldSystem( }); // Deploy the default program before Interfold so initialization can validate it. - const { mockE3Program: _mockE3Program } = - await ignition.deploy(MockE3ProgramModule); + const { mockE3Program: _mockE3Program } = await deploy(MockE3ProgramModule); const e3Program = MockE3ProgramFactory.connect( await _mockE3Program.getAddress(), owner, @@ -418,7 +418,7 @@ export async function deployInterfoldSystem( interfold: _interfold, interfoldLifecycle: _interfoldLifecycle, interfoldPricing: _interfoldPricing, - } = await ignition.deploy(InterfoldModule, { + } = await deploy(InterfoldModule, { parameters: { Interfold: { owner: ownerAddress, @@ -440,7 +440,7 @@ export async function deployInterfoldSystem( const interfoldPricing = await _interfoldPricing.getAddress(); await e3Program.setInterfold(interfoldAddress); - const { e3RefundManager: _e3RefundManager } = await ignition.deploy( + const { e3RefundManager: _e3RefundManager } = await deploy( E3RefundManagerModule, { parameters: { @@ -510,28 +510,30 @@ export async function deployInterfoldSystem( } // ── Mocks ───────────────────────────────────────────────────────────────── - const { mockComputeProvider: _mockComputeProvider } = await ignition.deploy( + const { mockComputeProvider: _mockComputeProvider } = await deploy( mockComputeProviderModule, ); const mockComputeProvider = _mockComputeProvider as unknown as MockComputeProvider; - const { mockDecryptionVerifier: _mockDecryptionVerifier } = - await ignition.deploy(MockDecryptionVerifierModule); + const { mockDecryptionVerifier: _mockDecryptionVerifier } = await deploy( + MockDecryptionVerifierModule, + ); const decryptionVerifier = MockDecryptionVerifierFactory.connect( await _mockDecryptionVerifier.getAddress(), owner, ); - const { mockCiphertextVerifier: _mockCiphertextVerifier } = - await ignition.deploy(MockCiphertextVerifierModule); + const { mockCiphertextVerifier: _mockCiphertextVerifier } = await deploy( + MockCiphertextVerifierModule, + ); const ciphertextVerifier = MockCiphertextVerifierFactory.connect( await _mockCiphertextVerifier.getAddress(), owner, ); const { mockPkVerifier: _mockPkVerifier } = - await ignition.deploy(MockPkVerifierModule); + await deploy(MockPkVerifierModule); const pkVerifier = MockPkVerifierFactory.connect( await _mockPkVerifier.getAddress(), owner, @@ -539,7 +541,7 @@ export async function deployInterfoldSystem( let circuitVerifier: MockCircuitVerifier | undefined; if (opts.deployCircuitVerifier) { - const { mockCircuitVerifier: _mockCircuitVerifier } = await ignition.deploy( + const { mockCircuitVerifier: _mockCircuitVerifier } = await deploy( MockCircuitVerifierModule, ); circuitVerifier = MockCircuitVerifierFactory.connect( diff --git a/packages/interfold-sdk/src/utils.ts b/packages/interfold-sdk/src/utils.ts index 2a2daf56da..6f0820c45d 100644 --- a/packages/interfold-sdk/src/utils.ts +++ b/packages/interfold-sdk/src/utils.ts @@ -71,7 +71,7 @@ export interface ComputeProviderParams { // Default compute provider configuration export const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = { - name: 'risc0', + name: 'openvm', parallel: false, batch_size: 2, } diff --git a/packages/interfold-sdk/tests/utils.test.ts b/packages/interfold-sdk/tests/utils.test.ts new file mode 100644 index 0000000000..8067f1dbc7 --- /dev/null +++ b/packages/interfold-sdk/tests/utils.test.ts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +import { describe, expect, it } from 'vitest' +import { DEFAULT_COMPUTE_PROVIDER_PARAMS } from '../src/utils' + +describe('default compute provider', () => { + it('selects OpenVM', () => { + expect(DEFAULT_COMPUTE_PROVIDER_PARAMS.name).toBe('openvm') + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13dd845943..4295c59533 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -825,9 +825,6 @@ importers: '@openzeppelin/contracts-upgradeable': specifier: 5.0.2 version: 5.0.2(@openzeppelin/contracts@5.3.0) - '@risc0/ethereum': - specifier: file:lib/risc0-ethereum - version: file:templates/default/lib/risc0-ethereum '@types/chai': specifier: ^4.2.0 version: 4.3.20 @@ -3388,9 +3385,6 @@ packages: '@reown/appkit@1.7.8': resolution: {integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==} - '@risc0/ethereum@file:templates/default/lib/risc0-ethereum': - resolution: {directory: templates/default/lib/risc0-ethereum, type: directory} - '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -14432,8 +14426,6 @@ snapshots: - utf-8-validate - zod - '@risc0/ethereum@file:templates/default/lib/risc0-ethereum': {} - '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/plugin-inject@5.0.5(rollup@4.62.3)': diff --git a/scripts/README.md b/scripts/README.md index dceaa095a8..7e8f340d10 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -527,22 +527,24 @@ Generated verifiers are automatically: ## Guest provenance -Two commands cover the RISC Zero compute guest. The full reviewer-facing procedure is +The provenance command records the OpenVM compute guest. The full reviewer-facing procedure is `docs/pages/build/e3-program/verify-compute-provider.mdx`. ### `generate-provenance-manifest.ts` -Emits the release record: source commit, lockfile digests, pinned revisions, RISC Zero version, -builder image tag and digest, guest ELF SHA-256, image ID, and — with an RPC — the deployed verifier -address, its runtime code digest, the underlying RISC Zero verifier, and the on-chain `imageId()`. +Records the source commit, lockfile digests, guest configuration, optimization patch, proving +artifacts, KZG parameters, and application commitments. With `--prover`, it checks the worker's +configured identity. With an RPC, it checks the protocol-to-receipt binding, application commitments, +and deployed Halo2 runtime against the checked artifact. These RPC checks do not send transactions. ```bash pnpm provenance:manifest -pnpm provenance:manifest --rpc --verifier
--out manifest.json +pnpm provenance:manifest --config --prover --rpc --verifier --out manifest.json ``` It prints `"complete": false` and lists unresolved fields when anything is missing. A release manifest must be complete. -Note: the SHA-256 of the ELF is **not** the image ID. SHA-256 checks binary integrity; the image ID -is computed from the loaded memory image. Both are recorded, for different purposes. +Artifact hashes check file integrity. Application commitments bind the OpenVM executable and VM +configuration. The receipt identity also binds the deployed Halo2 verifier address. These are +different checks. A complete manifest does not establish source reproducibility or audit coverage. diff --git a/scripts/clean.ts b/scripts/clean.ts index 74d2837fce..a4a0fd0fe2 100644 --- a/scripts/clean.ts +++ b/scripts/clean.ts @@ -38,7 +38,6 @@ class Cleaner { private setupSkips(): void { // Always skip the following folders. - this.skipPatterns.push('**/risc0-ethereum/**') this.skipPatterns.push('packages/interfold-contracts/artifacts/contracts/**/*.json') } diff --git a/scripts/generate-provenance-manifest.ts b/scripts/generate-provenance-manifest.ts index 49eca495f5..64d5fb6cac 100644 --- a/scripts/generate-provenance-manifest.ts +++ b/scripts/generate-provenance-manifest.ts @@ -5,337 +5,203 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -/** - * Build the release provenance manifest for the RISC Zero compute guest. - * - * `Risc0BfvCiphertextVerifier.imageId` is immutable and names exactly one guest image. A proof - * tells a verifier which guest ran; it says nothing about which source produced that guest. This - * manifest is the record that closes that gap, so a third party can start from a released tag and - * arrive at the deployed image ID. - * - * Local fields come from the working tree and the build output. Chain fields need an RPC endpoint - * and the deployed verifier address; without them the manifest still emits, with those fields null - * and `complete` false. - * - * pnpm provenance:manifest - * pnpm provenance:manifest --rpc https://... --verifier 0x... --out manifest.json - * - * The manifest is a record, not a check: it describes what was built and where it was deployed. - * Nothing in this repository verifies that the recorded image ID is the one the committed sources - * produce — that takes a reproducible Docker rebuild of the guest, and the reviewer-facing - * procedure is documented at docs/pages/build/e3-program/verify-compute-provider.mdx. - */ - -import { execFileSync } from 'child_process' -import { createHash } from 'crypto' -import fs from 'fs' -import path from 'path' - -const REPO_ROOT = path.resolve(__dirname, '..') -const SUPPORT = path.join(REPO_ROOT, 'crates', 'support') -const IMAGE_ID_SOL = path.join(SUPPORT, 'contracts', 'ImageID.sol') -const SUPPORT_DOCKERFILE = path.join(SUPPORT, 'Dockerfile') -const GUEST_BUILDER_DOCKERFILE = path.join(SUPPORT, 'methods', 'guest-builder.Dockerfile') - -interface Args { - rpc?: string - verifier?: string - out?: string -} - -function parseArgs(argv: string[]): Args { +/** Record the OpenVM build, checked application identity, and deployed verifier bindings. */ +import { execFileSync } from 'node:child_process' +import { createHash } from 'node:crypto' +import { createReadStream, existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs' +import { createRequire } from 'node:module' +import path from 'node:path' + +const root = path.resolve(__dirname, '..') +const requireContracts = createRequire(path.join(root, 'packages/interfold-contracts/package.json')) +const { AbiCoder, Contract, FetchRequest, JsonRpcProvider, getAddress, id, keccak256 } = requireContracts('ethers') +type Args = Partial> + +function parseArgs(): Args { const args: Args = {} - for (let i = 0; i < argv.length; i += 1) { - const flag = argv[i] - const value = argv[i + 1] - if (flag === '--rpc' || flag === '--verifier' || flag === '--out') { - if (!value || value.startsWith('--')) { - throw new Error(`${flag} needs a value`) - } - args[flag.slice(2) as keyof Args] = value - i += 1 - } else { - throw new Error(`unknown argument '${flag}'`) + const values = process.argv.slice(2) + for (let i = 0; i < values.length; i += 2) { + const name = values[i].slice(2) as keyof Args + if (!['config', 'prover', 'rpc', 'verifier', 'out'].includes(name) || !values[i].startsWith('--')) { + throw new Error('Unknown argument: ' + values[i]) } + if (!values[i + 1] || values[i + 1].startsWith('--')) throw new Error('Missing value: ' + values[i]) + args[name] = values[i + 1] } - if (args.rpc && !args.verifier) throw new Error('--rpc also needs --verifier') - if (args.verifier && !args.rpc) throw new Error('--verifier also needs --rpc') + if (Boolean(args.rpc) !== Boolean(args.verifier)) throw new Error('Supply --rpc and --verifier together') + if (args.prover && !args.config) throw new Error('--prover requires --config') return args } -function sh(command: string, commandArgs: string[]): string | null { - try { - return execFileSync(command, commandArgs, { - cwd: REPO_ROOT, - encoding: 'utf8', - stdio: ['ignore', 'pipe', 'ignore'], - }).trim() - } catch { - return null - } -} - -function readIfPresent(file: string): string | null { - return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null -} - -function sha256File(file: string): string | null { - if (!fs.existsSync(file)) return null - return createHash('sha256').update(fs.readFileSync(file)).digest('hex') -} - -function firstMatch(text: string | null, pattern: RegExp): string | null { - if (!text) return null - const match = text.match(pattern) - return match ? match[1] : null -} - -/** Collects every Interfold git pin the guest workspace reads, so a split pin is visible. */ -function pinnedRevisions(): Record { - const manifests = [path.join(SUPPORT, 'Cargo.toml'), path.join(SUPPORT, 'methods', 'guest', 'Cargo.toml')] - const pins: Record = {} - for (const manifest of manifests) { - const text = readIfPresent(manifest) - if (!text) continue - const found = [...text.matchAll(/rev = "([0-9a-f]{40})"/g)].map((m) => m[1]) - pins[path.relative(REPO_ROOT, manifest)] = [...new Set(found)] - } - return pins -} - -/** - * Resolves the RISC Zero guest builder image. - * - * `risc0-build` reads a bare tag, not an image reference: `docker_container_tag()` returns - * `RISC0_DOCKER_CONTAINER_TAG`, else the value the caller set on `DockerOptions`, else its own - * `DEFAULT_DOCKER_TAG` (`risc0-build-3.0.3/src/config.rs:59-70`), and `docker.rs:145-149` then - * builds `risczero/risc0-guest-builder:` from it. Both sources here are therefore suffixes, - * and the repository prefix belongs on the outside of the choice. - * - * `crates/support/methods/build.rs` builds the checked-in Protobuf layer and always sets the - * second value to `interfold-r0.-protoc-v1`. The compiled-in default is therefore - * unreachable from this repository. - * - * The tag is mutable and does not identify a build on its own, so record the resolved digest - * whenever Docker can supply it. - * - * Without a toolchain there is no builder to name, override or not. `guest_builder_tag` panics on a - * missing `ARG RISC0_TOOLCHAIN` and asserts on an empty one (`build.rs:67-80`), and it runs only - * inside `if use_docker()` (`build.rs:90-95`). A tree that cannot supply one therefore either - * failed the Docker build before `risc0-build` read the variable, or built locally and pulled no - * image at all. Reporting the override there would name a builder nothing used; leaving the field - * unresolved says what is true and keeps the manifest incomplete. - */ -function builderImage(guestToolchain: string | null) { - // Trim before the check, not after, matching the assert at `build.rs:71-77`. A whitespace-only - // value would otherwise name the image `risczero/risc0-guest-builder:r0.`. - const toolchain = guestToolchain?.trim() || null - if (!toolchain) return { tag: null, digest: null } - const suffix = process.env.RISC0_DOCKER_CONTAINER_TAG?.trim() || `interfold-r0.${toolchain}-protoc-v1` - const tag = `risczero/risc0-guest-builder:${suffix}` - const digest = sh('docker', ['image', 'inspect', '--format', '{{index .RepoDigests 0}}', tag]) - return { tag, digest } -} - -/** Reads the guest ELF path out of the generated Elf.sol, which is not committed. */ -function guestElf() { - const elfSol = readIfPresent(path.join(SUPPORT, 'tests', 'Elf.sol')) - const elfPath = firstMatch(elfSol, /"([^"]+program\.bin)"/) - if (!elfPath) { - return { path: null, sha256: null, note: 'Elf.sol absent; build the guest first' } - } - const sha256 = sha256File(elfPath) - return { - path: elfPath, - sha256, - note: sha256 ? null : 'Elf.sol names a path that does not exist on this machine', - } -} - -/** - * How long a single RPC call may take before it counts as unresolved. - * - * `fetch` has no default timeout. An endpoint that accepts the connection and never answers would - * hang instead of leaving the field unresolved, and a record that never finishes says less than one - * that names what it could not reach. - */ -const RPC_TIMEOUT_MS = 15_000 - -async function rpcCall(rpc: string, method: string, params: unknown[]): Promise { +function command(binary: string, args: string[]): string | null { try { - const response = await fetch(rpc, { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), - signal: AbortSignal.timeout(RPC_TIMEOUT_MS), - }) - const body = (await response.json()) as { result?: string; error?: unknown } - if (body.error || typeof body.result !== 'string') return null - return body.result + return execFileSync(binary, args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 60_000 }).trim() } catch { return null } } -/** `keccak256("imageId()")[0..4]` and `keccak256("risc0Verifier()")[0..4]`. */ -const SELECTOR_IMAGE_ID = '0xef3f7dd5' -const SELECTOR_RISC0_VERIFIER = '0x5c9770c5' - -/** - * A `0x`-prefixed hex string of exactly `bytes` bytes, or null. - * - * An RPC result is only known to be a string. Everything downstream treats non-null as resolved, so - * a malformed answer that survives this far reads as a verified fact — which is the one thing a - * fail-closed manifest must not do. - */ -function hexOfLength(value: string | null, bytes: number): string | null { - if (!value) return null - // Lowercased, not returned as received. Hex is case-insensitive, but `onchainImageId` is later - // compared against `ImageID.sol` as a plain string — an uppercase RPC answer would read as a - // mismatch and make the manifest incomplete for no reason. - return new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value) ? value.toLowerCase() : null -} - -/** Any `0x`-prefixed hex string with a whole number of bytes, lowercased, or null. */ -function hexBytes(value: string | null): string | null { - if (!value) return null - return /^0x([0-9a-fA-F]{2})*$/.test(value) ? value.toLowerCase() : null +async function digest(file: string): Promise { + if (!existsSync(file)) return null + const hash = createHash('sha256') + for await (const chunk of createReadStream(file)) hash.update(chunk) + return hash.digest('hex') } -async function chainFacts(rpc: string, verifier: string) { - const code = hexBytes(await rpcCall(rpc, 'eth_getCode', [verifier, 'latest'])) - const codePresent = Boolean(code && code !== '0x') - // SHA-256, not keccak256: Node's crypto has no keccak256, and any fixed digest serves the - // purpose here as long as the manifest names which one it is. - const runtimeCodeSha256 = - code && codePresent - ? `0x${createHash('sha256') - .update(Buffer.from(code.slice(2), 'hex')) - .digest('hex')}` - : null - - // Both calls return one ABI word. An image ID is that word; an address is its low 20 bytes. - const onchainImageId = hexOfLength(await rpcCall(rpc, 'eth_call', [{ to: verifier, data: SELECTOR_IMAGE_ID }, 'latest']), 32) - const underlyingWord = hexOfLength(await rpcCall(rpc, 'eth_call', [{ to: verifier, data: SELECTOR_RISC0_VERIFIER }, 'latest']), 32) - - const chainIdHex = hexBytes(await rpcCall(rpc, 'eth_chainId', [])) - const chainIdValue = chainIdHex ? Number.parseInt(chainIdHex, 16) : Number.NaN - - return { - // `Number.isSafeInteger` rather than a null check: `parseInt` yields NaN for a malformed - // answer, NaN passes `!== null`, and `JSON.stringify` then writes it as null — a manifest that - // claims to be complete while recording no chain. - chainId: Number.isSafeInteger(chainIdValue) ? chainIdValue : null, - ciphertextVerifier: verifier, - ciphertextVerifierRuntimeCodeSha256: runtimeCodeSha256, - ciphertextVerifierCodePresent: codePresent, - underlyingRisc0Verifier: underlyingWord ? `0x${underlyingWord.slice(-40)}` : null, - onchainImageId, +async function parameterDigests(directory: string, relative = ''): Promise> { + const result: Record = {} + for (const entry of readdirSync(path.join(directory, relative), { withFileTypes: true })) { + const name = path.join(relative, entry.name) + if (entry.isDirectory()) Object.assign(result, await parameterDigests(directory, name)) + else if (entry.isFile()) result[name] = await digest(path.join(directory, name)) + else throw new Error('The parameter directory must contain only regular files and directories') } + return result } async function main() { - const args = parseArgs(process.argv.slice(2)) - - const supportDockerfile = readIfPresent(SUPPORT_DOCKERFILE) - const guestBuilderDockerfile = readIfPresent(GUEST_BUILDER_DOCKERFILE) - const risc0Version = firstMatch(supportDockerfile, /^ARG RISC0_VERSION=(.*)$/m) - const risc0Toolchain = firstMatch(guestBuilderDockerfile, /^ARG RISC0_TOOLCHAIN=(.*)$/m) - // Lowercased for the same reason the RPC answers are: Solidity accepts either case, and this - // value is compared against `deployment.onchainImageId` as a plain string. - const committedImageId = firstMatch(readIfPresent(IMAGE_ID_SOL), /(0x[0-9a-fA-F]{64})/)?.toLowerCase() ?? null - - const elf = guestElf() - const chain = args.rpc && args.verifier ? await chainFacts(args.rpc, args.verifier) : null - - const manifest = { - schema: 'interfold.compute-provider-provenance/1', - generatedFrom: { - sourceCommit: sh('git', ['rev-parse', 'HEAD']), - sourceDescribe: sh('git', ['describe', '--tags', '--always', '--dirty']), - treeClean: sh('git', ['status', '--porcelain']) === '', - }, - build: { - risc0Version, - risc0GuestToolchain: risc0Toolchain, - hostToolchain: firstMatch(readIfPresent(path.join(REPO_ROOT, 'rust-toolchain.toml')), /channel = "([^"]+)"/), - builderImage: builderImage(risc0Toolchain), - pinnedRevisions: pinnedRevisions(), - // Why the guest is pinned where it is, and what that pin does and does not certify. A - // consumer reading only a commit hash would reasonably assume the code behind it was - // audited; for the guest, it was not. - auditBaseline: { - commit: 'c2097da61b4d07c4ce83840393ff4e9f171eefb4', - report: 'packages/interfold-contracts/audits/20260714-Interfold - Zenith Audit Report.pdf', - mitigationReviewCommit: 'c64bcfb890b596e626ea6578c5fbd53f808c3b43', - guestInAuditScope: false, - note: 'The 2026-08-17 Zenith audit covered six Solidity files and no Rust. crates/compute-provider, the RISC Zero guest, crates/zk-helpers, and Risc0BfvCiphertextVerifier.sol were outside both the audit and the mitigation review.', - }, - lockfiles: { - 'crates/support/Cargo.lock': sha256File(path.join(SUPPORT, 'Cargo.lock')), - 'crates/support/methods/guest/Cargo.lock': sha256File(path.join(SUPPORT, 'methods', 'guest', 'Cargo.lock')), - }, - }, - guest: { - elfPath: elf.path, - elfSha256: elf.sha256, - elfNote: elf.note, - // The SHA-256 of the ELF is a binary integrity check. It is NOT the image ID, which is - // computed from the loaded memory image. Both are recorded; neither substitutes for the other. - imageId: committedImageId, - }, - deployment: chain, - } - - // A deployment object exists even when every RPC call failed, so completeness is decided by the - // fields themselves. Without this a timed-out RPC would produce a manifest that reads as verified. - const deploymentResolved = - chain !== null && - chain.chainId !== null && - chain.ciphertextVerifierCodePresent && - chain.ciphertextVerifierRuntimeCodeSha256 !== null && - chain.underlyingRisc0Verifier !== null && - chain.onchainImageId !== null - + const args = parseArgs() const unresolved: string[] = [] - if (!manifest.guest.elfSha256) unresolved.push('guest.elfSha256') - if (!manifest.build.builderImage.digest) unresolved.push('build.builderImage.digest') - if (!chain) { - unresolved.push('deployment (pass --rpc and --verifier)') - } else if (!deploymentResolved) { - if (chain.chainId === null) unresolved.push('deployment.chainId') - if (!chain.ciphertextVerifierCodePresent) unresolved.push('deployment.ciphertextVerifier (no code at address)') - if (chain.ciphertextVerifierRuntimeCodeSha256 === null) unresolved.push('deployment.ciphertextVerifierRuntimeCodeSha256') - if (chain.underlyingRisc0Verifier === null) unresolved.push('deployment.underlyingRisc0Verifier') - if (chain.onchainImageId === null) unresolved.push('deployment.onchainImageId') - } - - // The recorded image ID must also be the one deployed, or the manifest describes a different - // artefact from the one in use. - if (chain?.onchainImageId && committedImageId && chain.onchainImageId !== committedImageId) { - unresolved.push(`deployment.onchainImageId (${chain.onchainImageId}) does not match ImageID.sol (${committedImageId})`) - } - - const output = { ...manifest, complete: unresolved.length === 0, unresolved } - const json = `${JSON.stringify(output, null, 2)}\n` - - if (args.out) { - fs.writeFileSync(path.resolve(REPO_ROOT, args.out), json) - console.log(`provenance manifest written to ${args.out}`) - } else { - process.stdout.write(json) - } + const files = [ + 'Cargo.lock', + 'crates/support/Cargo.lock', + 'crates/support/openvm/guest/Cargo.lock', + 'crates/support/openvm/prover/Cargo.lock', + 'rust-toolchain.toml', + 'crates/support/openvm/guest/openvm.toml', + 'crates/support/openvm/fhe-optimizations.patch', + ] + const sourceDigests = Object.fromEntries(await Promise.all(files.map(async (file) => [file, await digest(path.join(root, file))]))) + const sourceCommit = command('git', ['rev-parse', 'HEAD']) + const sourceStatus = command('git', ['status', '--porcelain']) + if (!sourceCommit || sourceStatus !== '') unresolved.push('source must be a clean Git checkout') + for (const [file, hash] of Object.entries(sourceDigests)) if (!hash) unresolved.push('source artifact: ' + file) + + let artifacts: Record | null = null + let parameters: Record | null = null + let commitments: { app_exe_commit: string; app_vm_commit: string } | null = null + let workerChecked = false + let deployment: Record | null = null + let verifierArtifact: { bytecode: string } | undefined + if (args.config) { + const configPath = path.resolve(args.config) + const config = JSON.parse(readFileSync(configPath, 'utf8')) + commitments = config.app_commit + if (!commitments || ![commitments.app_exe_commit, commitments.app_vm_commit].every((value) => /^0x[0-9a-fA-F]{64}$/.test(value))) { + throw new Error('The worker configuration must contain both 32-byte application commitments') + } + artifacts = {} + for (const name of ['app_pk', 'executable', 'aggregation_pk', 'halo2_pk', 'verifier_artifact']) { + if (typeof config[name] !== 'string' || !path.isAbsolute(config[name])) throw new Error('Invalid artifact path: ' + name) + artifacts[name] = await digest(config[name]) + if (!artifacts[name]) unresolved.push('artifact: ' + name) + } + if (artifacts.verifier_artifact !== config.verifier_sha256) throw new Error('Verifier artifact checksum mismatch') + verifierArtifact = JSON.parse(readFileSync(config.verifier_artifact, 'utf8')) + if (!path.isAbsolute(config.halo2_params_dir)) throw new Error('The parameter directory must be an absolute path') + parameters = await parameterDigests(config.halo2_params_dir) + if (Object.keys(parameters).length === 0) unresolved.push('Halo2 parameters') + if (args.prover) { + const prover = path.resolve(args.prover) + artifacts.worker = await digest(prover) + workerChecked = command(prover, ['check', configPath]) !== null + } + if (!workerChecked) unresolved.push('worker identity check (supply a working --prover)') + } else unresolved.push('worker configuration (supply --config)') + + if (args.rpc && args.verifier) { + const request = new FetchRequest(args.rpc) + request.timeout = 15_000 + const provider = new JsonRpcProvider(request) + try { + const protocolAddress = getAddress(args.verifier) + const protocol = new Contract( + protocolAddress, + ['function imageId() view returns(bytes32)', 'function openVmVerifier() view returns(address)'], + provider, + ) + const receiptAddress = await protocol.openVmVerifier() + const receipt = new Contract( + receiptAddress, + [ + 'function imageId() view returns(bytes32)', + 'function verifier() view returns(address)', + 'function appExeCommit() view returns(bytes32)', + 'function appVmCommit() view returns(bytes32)', + ], + provider, + ) + const halo2Address = await receipt.verifier() + const [protocolCode, receiptCode, halo2Code] = await Promise.all( + [protocolAddress, receiptAddress, halo2Address].map((address) => provider.getCode(address)), + ) + if ([protocolCode, receiptCode, halo2Code].includes('0x')) throw new Error('A configured verifier has no deployed code') + const [protocolId, receiptId, exe, vm, network] = await Promise.all([ + protocol.imageId(), + receipt.imageId(), + receipt.appExeCommit(), + receipt.appVmCommit(), + provider.getNetwork(), + ]) + const expectedId = keccak256( + AbiCoder.defaultAbiCoder().encode( + ['bytes32', 'address', 'bytes32', 'bytes32'], + [id('INTERFOLD_OPENVM_RECEIPT_V1'), halo2Address, exe, vm], + ), + ) + if (protocolId !== receiptId || receiptId !== expectedId) throw new Error('The deployed receipt identity is inconsistent') + if ( + !commitments || + exe.toLowerCase() !== commitments.app_exe_commit.toLowerCase() || + vm.toLowerCase() !== commitments.app_vm_commit.toLowerCase() + ) { + throw new Error('The deployed application commitments differ from the configured guest') + } + if (!verifierArtifact || !/^(0x)?[0-9a-fA-F]+$/.test(verifierArtifact.bytecode)) throw new Error('Missing verifier creation bytecode') + // Simulate creation without sending a transaction, then compare the resulting runtime. + const runtime = await provider.call({ data: '0x' + verifierArtifact.bytecode.replace(/^0x/, '') }) + if (keccak256(runtime) !== keccak256(halo2Code)) throw new Error('The deployed Halo2 runtime differs from the checked artifact') + deployment = { + chainId: network.chainId.toString(), + ciphertextVerifier: protocolAddress, + receiptVerifier: receiptAddress, + halo2Verifier: halo2Address, + imageId: protocolId, + ciphertextVerifierCodeHash: keccak256(protocolCode), + receiptVerifierCodeHash: keccak256(receiptCode), + halo2VerifierCodeHash: keccak256(halo2Code), + identityMatches: true, + halo2ArtifactMatches: true, + } + } catch (error) { + unresolved.push('deployment check: ' + String(error)) + } finally { + provider.destroy() + } + } else unresolved.push('deployment (supply --rpc and --verifier)') - if (unresolved.length > 0) { - console.error( - `\n⚠️ incomplete manifest. Unresolved: ${unresolved.join(', ')}\n` + - ` An incomplete manifest records an unfinished verification, not a passing result.\n` + - ` See docs/pages/build/e3-program/verify-compute-provider.mdx.`, - ) + const manifest = { + schema: 'interfold.openvm-provenance/1', + backend: 'openvm', + source: { commit: sourceCommit, clean: sourceStatus === '', sha256: sourceDigests }, + artifactsSha256: artifacts, + halo2ParametersSha256: parameters, + appCommit: commitments, + workerIdentityChecked: workerChecked, + deployment, + complete: unresolved.length === 0, + unresolved, + auditStatus: 'The compute implementation and its OpenVM verifier integration are not audited.', + sourceReproductionChecked: false, + note: 'Artifact and identity checks do not establish reproducibility. Independently rebuild the guest from the recorded clean source.', } + const output = JSON.stringify(manifest, null, 2) + '\n' + if (args.out) writeFileSync(path.resolve(args.out), output, { flag: 'wx' }) + else process.stdout.write(output) + if (unresolved.length) console.error('Incomplete OpenVM provenance: ' + unresolved.join('; ')) } -main().catch((error: unknown) => { - console.error(`generate-provenance-manifest: ${(error as Error).message}`) - process.exit(1) +main().catch((error) => { + console.error(String(error)) + process.exitCode = 1 }) diff --git a/scripts/run-openvm.sh b/scripts/run-openvm.sh new file mode 100644 index 0000000000..23c455001a --- /dev/null +++ b/scripts/run-openvm.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-3.0-only +set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +command="${1:-}" +shift || true +case "$command" in + setup-fhe) exec node "$ROOT/scripts/setup-openvm-fhe.mjs" "$@" ;; + cli-build) + exec cargo build --locked --release --manifest-path "$ROOT/Cargo.toml" -p e3-cli --bin interfold "$@" + ;; + fixture) + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/crisp-server}" + exec cargo run --locked --release --manifest-path "$ROOT/examples/CRISP/Cargo.toml" -p e3-user-program --example openvm_fixture -- "$@" + ;; + crisp-server-build|crisp-server-test) + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/crisp-server}" + exec cargo "${command#crisp-server-}" --locked --manifest-path "$ROOT/examples/CRISP/Cargo.toml" -p crisp "$@" + ;; + service-build|service-test|service-check) + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/service}" + exec cargo "${command#service-}" --locked --manifest-path "$ROOT/crates/support/Cargo.toml" "$@" + ;; + service-start) + : "${OPENVM_PROVER_BIN:?Set OPENVM_PROVER_BIN}" + : "${OPENVM_PROVER_CONFIG:?Set OPENVM_PROVER_CONFIG}" + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/service}" + exec cargo run --locked --release --manifest-path "$ROOT/crates/support/Cargo.toml" -p e3-support-app -- "$@" + ;; + prover-build|prover-test|prover-check) + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/prover}" + exec cargo "${command#prover-}" --locked --release --manifest-path "$ROOT/crates/support/openvm/prover/Cargo.toml" "$@" + ;; + prover) + export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/prover}" + exec cargo run --locked --release --manifest-path "$ROOT/crates/support/openvm/prover/Cargo.toml" -- "$@" + ;; + guest) + export CARGO_TARGET_DIR="$ROOT/target/openvm/guest" + export RUSTFLAGS="${RUSTFLAGS:-} --cfg crisp_openvm --cfg crisp_fhe_optimized" + export OPENVM_BUILD_LOCKED=1 + cd "$ROOT/crates/support/openvm/guest" + exec cargo openvm "$@" + ;; + contract-test) + exec pnpm --filter @crisp-e3/contracts test --network default tests/openvm-receipt.test.ts tests/crisp.journal.test.ts "$@" + ;; + proof-test) + OPENVM_REQUIRE_PROOF_TEST=1 exec pnpm --filter @crisp-e3/contracts test --network default tests/openvm-proof.test.ts "$@" + ;; + service-e2e) + OPENVM_E2E_ENABLED=1 exec pnpm --filter @crisp-e3/contracts test --network localhost tests/openvm-service.test.ts "$@" + ;; + *) echo 'Usage: pnpm openvm setup-fhe|cli-build|fixture|crisp-server-build|crisp-server-test|service-build|service-test|service-check|service-start|prover-build|prover-test|prover-check|prover|guest|contract-test|proof-test|service-e2e [arguments]' >&2; exit 2 ;; +esac diff --git a/scripts/setup-openvm-fhe.mjs b/scripts/setup-openvm-fhe.mjs new file mode 100644 index 0000000000..0b95b424d6 --- /dev/null +++ b/scripts/setup-openvm-fhe.mjs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +import { spawnSync } from 'node:child_process' +import { existsSync, mkdirSync, readFileSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const root = fileURLToPath(new URL('../', import.meta.url)) +const destination = path.join(root, 'target/openvm/fhe') +const revision = 'f2c1d2258fbeef6dbdf5ade68438203fd80a648e' +const patch = path.join(root, 'crates/support/openvm/fhe-optimizations.patch') +function git(args, cwd = destination) { + const result = spawnSync('git', args, { cwd, encoding: 'utf8' }) + if (result.error || result.status !== 0) throw result.error ?? new Error(result.stderr) + return result.stdout.trimEnd() +} +if (!existsSync(destination)) { + mkdirSync(path.dirname(destination), { recursive: true }) + git(['clone', '--filter=blob:none', '--no-checkout', 'https://github.com/gnosisguild/fhe.rs.git', destination], root) + git(['checkout', '--detach', revision]) +} +if (git(['rev-parse', 'HEAD']) !== revision) throw new Error(`The FHE checkout must use revision ${revision}`) +const expected = readFileSync(patch, 'utf8').trimEnd() +const actual = git(['diff', 'HEAD']) +if (actual && actual !== expected) throw new Error('The FHE checkout contains changes that differ from the OpenVM patch') +if (!actual) { + git(['apply', '--check', patch]) + git(['apply', patch]) +} +if (git(['diff', 'HEAD']) !== expected) throw new Error('The applied FHE patch does not match the OpenVM patch') +console.log(`FHE ${revision}: OpenVM patch verified`) diff --git a/templates/default/.gitignore b/templates/default/.gitignore index d060832137..ce297d7abc 100644 --- a/templates/default/.gitignore +++ b/templates/default/.gitignore @@ -20,8 +20,7 @@ node_modules /target -# Ignore risc0 files -tests/Elf.sol +.interfold/generated/ /deployments diff --git a/templates/default/.gitignore.bak b/templates/default/.gitignore.bak index 455e2fb7e1..f58beb4747 100644 --- a/templates/default/.gitignore.bak +++ b/templates/default/.gitignore.bak @@ -19,9 +19,5 @@ node_modules /coverage /coverage.json -# Ignore risc0 files -contracts/ImageID.sol -tests/Elf.sol - # Hardhat Ignition default folder for deployments against a local node ignition/deployments/chain-31337 diff --git a/templates/default/.gitmodules.bak b/templates/default/.gitmodules.bak deleted file mode 100644 index e056661b1d..0000000000 --- a/templates/default/.gitmodules.bak +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/risc0-ethereum"] - path = lib/risc0-ethereum - url = https://github.com/gnosisguild/risc0-ethereum diff --git a/templates/default/.interfold/generated/contracts/ImageID.sol b/templates/default/.interfold/generated/contracts/ImageID.sol deleted file mode 100644 index c0eb4923f0..0000000000 --- a/templates/default/.interfold/generated/contracts/ImageID.sol +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2024 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 - -// This file is automatically generated - -pragma solidity ^0.8.20; - -library ImageID { - bytes32 public constant PROGRAM_ID = bytes32(0xaf928ebf39fec4696c3f41f473a1a9473b67d723c6373149c6ab99ba4c1a76ef); -} diff --git a/templates/default/Cargo.lock b/templates/default/Cargo.lock index e8ab2ad237..eb0ad49e68 100644 --- a/templates/default/Cargo.lock +++ b/templates/default/Cargo.lock @@ -1380,7 +1380,6 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "risc0-bigint2", "sha3 0.10.8", "taceo-poseidon2", ] @@ -2207,12 +2206,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "include_bytes_aligned" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" - [[package]] name = "indexmap" version = "2.14.0" @@ -3315,16 +3308,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "risc0-bigint2" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87f5f7494a2242cead2750b7ce2b8522c1be83dee268479f1c12ed521eaf595" -dependencies = [ - "include_bytes_aligned", - "stability", -] - [[package]] name = "rlp" version = "0.5.2" @@ -3741,16 +3724,6 @@ dependencies = [ "der", ] -[[package]] -name = "stability" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" -dependencies = [ - "quote", - "syn 2.0.117", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" diff --git a/templates/default/README.md b/templates/default/README.md index d4f4ea5918..603a99d0e7 100644 --- a/templates/default/README.md +++ b/templates/default/README.md @@ -11,7 +11,6 @@ Before getting started, ensure you have installed: - [Rust](https://rust-lang.org/tools/install/) - [NodeJS](https://nodejs.org/en/download) -- [RiscZero](https://dev.risczero.com/api/zkvm/install) - [pnpm](https://pnpm.io) - [Metamask](https://metamask.io) @@ -22,26 +21,16 @@ As system requirements: ## Quick Start -### (optional) Install RISC Zero Toolchain +### Configure OpenVM -Next, install `rzup` for the `cargo-risczero` toolchain. +The program server uses OpenVM. Build a guest for your program policy, prepare its proving keys, +and configure `program.openvm` in `interfold.config.yaml`. See the repository's +[`crates/support/openvm/README.md`](../../crates/support/openvm/README.md) for worker setup and +verifier deployment. The reference CRISP guest cannot prove an unrelated template policy. -```sh -# Install rzup -curl -L https://risczero.com/install | bash - -# Install RISC Zero toolchain -rzup install cargo-risczero -``` - -Verify the installation was successful by running: - -```sh -cargo risczero --version -``` - -At this point, you should have all the tools required to develop and deploy an application with -[RISC Zero](https://www.risczero.com). +Contract deployment requires both application commitments and either a checksummed Halo2 verifier +artifact or an existing verifier address with its expected runtime code hash. Missing settings stop +deployment; they do not select a mock verifier. ### Install Metamask @@ -96,22 +85,25 @@ This creates a complete E3 project with: ### Compile your E3 Program -First, compile your E3 program to build the Risc0 zkvm image: +Build the configured native program service: ```bash interfold program compile ``` -This builds the Risc0 zkvm image that will be deployed on the blockchain and used for verification -of the final proof. +This command does not rebuild the guest or its keys. Rebuild and deploy those artifacts separately +when the proved program changes. -If you want to avoid the proof or you have trouble with Risc0 zkvm installation, you can run it in -dev mode (no proof). +For an explicitly unproved local test, start the development runner: ```bash interfold program start --dev true ``` +The template's integration-test script also sets `TEMPLATE_UNPROVED_TEST=1`. Only chain ID 31337 +accepts that deployment setting. This test uses a mock receipt verifier and is not evidence of a +valid OpenVM proof. Normal startup does not set either flag. + ### Start the Development Environment Launch all services with one command: diff --git a/templates/default/contracts/Mocks/MockOpenVmReceiptVerifier.sol b/templates/default/contracts/Mocks/MockOpenVmReceiptVerifier.sol new file mode 100644 index 0000000000..0e8cd73ed2 --- /dev/null +++ b/templates/default/contracts/Mocks/MockOpenVmReceiptVerifier.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +pragma solidity 0.8.28; + +import { IOpenVmReceiptVerifier } from "@interfold/contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol"; + +/// @notice Unproved execution for isolated local integration tests only. +contract MockOpenVmReceiptVerifier is IOpenVmReceiptVerifier { + bytes32 public constant imageId = keccak256("INTERFOLD_LOCAL_UNPROVED_TEST"); + function verify(bytes calldata, bytes32, bytes32) external pure override {} +} diff --git a/templates/default/contracts/Mocks/MockRISC0Verifier.sol b/templates/default/contracts/Mocks/MockRISC0Verifier.sol deleted file mode 100644 index 566ff34694..0000000000 --- a/templates/default/contracts/Mocks/MockRISC0Verifier.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -pragma solidity 0.8.28; - -import { IRiscZeroVerifier, Receipt } from "risc0/IRiscZeroVerifier.sol"; - -contract MockRISC0Verifier is IRiscZeroVerifier { - function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view override {} - - function verifyIntegrity(Receipt calldata receipt) external view override {} -} diff --git a/templates/default/contracts/MyProgram.sol b/templates/default/contracts/MyProgram.sol index 42a081b1c0..e530741047 100755 --- a/templates/default/contracts/MyProgram.sol +++ b/templates/default/contracts/MyProgram.sol @@ -5,11 +5,11 @@ // or FITNESS FOR A PARTICULAR PURPOSE. pragma solidity 0.8.28; -import { IRiscZeroVerifier } from "risc0/IRiscZeroVerifier.sol"; +import { IOpenVmReceiptVerifier } from "@interfold/contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol"; import { IE3Program } from "@interfold/contracts/contracts/interfaces/IE3Program.sol"; import { IInterfold } from "@interfold/contracts/contracts/interfaces/IInterfold.sol"; import { E3 } from "@interfold/contracts/contracts/interfaces/IE3.sol"; -import { Risc0ComputeProof } from "@interfold/contracts/contracts/lib/Risc0ComputeProof.sol"; +import { OpenVmComputeProof } from "@interfold/contracts/contracts/lib/OpenVmComputeProof.sol"; import { IDataAvailabilityVerifier, IE3ProgramDataAvailability } from "@interfold/contracts/contracts/interfaces/IDataAvailabilityVerifier.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; @@ -24,7 +24,7 @@ contract MyProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownable { // State variables IInterfold public interfold; - IRiscZeroVerifier public verifier; + IOpenVmReceiptVerifier public verifier; bytes32 public imageId; // Mappings @@ -45,11 +45,11 @@ contract MyProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownable { event InputPublished(uint256 indexed e3Id, bytes data, uint256 index); - /// @notice Initialize the contract, binding it to a specified RISC Zero verifier. + /// @notice Bind the program to its OpenVM receipt verifier. /// @param _interfold The Interfold contract address - /// @param _verifier The RISC Zero verifier address + /// @param _verifier The OpenVM receipt verifier address /// @param _imageId The image ID for the guest program - constructor(IInterfold _interfold, IRiscZeroVerifier _verifier, bytes32 _imageId) Ownable(msg.sender) { + constructor(IInterfold _interfold, IOpenVmReceiptVerifier _verifier, bytes32 _imageId) Ownable(msg.sender) { require(address(_verifier) != address(0), VerifierAddressZero()); interfold = _interfold; @@ -118,9 +118,9 @@ contract MyProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownable { E3 memory e3 = interfold.getE3(e3Id); bytes32 paramsHash = paramsHashes[e3Id]; bytes32 inputRoot = bytes32(inputs[e3Id]._root()); - Risc0ComputeProof.Proof memory computeProof = Risc0ComputeProof.decode(proof); + OpenVmComputeProof.Proof memory computeProof = OpenVmComputeProof.decode(proof); if (computeProof.paramsHash != paramsHash || computeProof.inputRoot != inputRoot) revert InvalidComputeContext(); - bytes memory journal = Risc0ComputeProof.journal( + bytes memory journal = OpenVmComputeProof.journal( bytes32(block.chainid), bytes32(uint256(uint160(address(interfold)))), bytes32(e3Id), diff --git a/templates/default/deploy/default.ts b/templates/default/deploy/default.ts index d1b89e98fd..9805ee0186 100644 --- a/templates/default/deploy/default.ts +++ b/templates/default/deploy/default.ts @@ -4,7 +4,13 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { getDeploymentChain, readDeploymentArgs, storeDeploymentArgs, updateE3Config } from '@interfold/contracts/scripts' +import { + deployOpenVmReceiptVerifier, + getDeploymentChain, + readDeploymentArgs, + storeDeploymentArgs, + updateE3Config, +} from '@interfold/contracts/scripts' import { Interfold__factory as InterfoldFactory } from '@interfold/contracts/types' import { ensureTemplateCwd, INTERFOLD_CONFIG_FILE } from '../scripts/template-paths' import { MyProgram__factory as MyProgramFactory } from '../types/factories/contracts' @@ -38,23 +44,27 @@ export const deployTemplate = async () => { throw new Error('PoseidonT3 address not found, it must be deployed first') } - const verifier = await ethers.deployContract('MockRISC0Verifier') + const unprovedTest = process.env.TEMPLATE_UNPROVED_TEST === '1' + if (unprovedTest && (await ethers.provider.getNetwork()).chainId !== 31337n) { + throw new Error('TEMPLATE_UNPROVED_TEST requires the isolated local chain') + } + let verifier + let verifierConstructorArgs: Record = {} + if (unprovedTest) { + verifier = await ethers.deployContract('MockOpenVmReceiptVerifier') + } else { + const deployed = await deployOpenVmReceiptVerifier(ethers) + verifier = deployed.receipt + verifierConstructorArgs = { verifier: deployed.halo2Verifier, appExeCommit: deployed.appExeCommit, appVmCommit: deployed.appVmCommit } + } await verifier.waitForDeployment() - - const imageId = await ethers.deployContract('ImageID') - await imageId.waitForDeployment() - + const programId = await verifier.imageId() storeDeploymentArgs( - { - address: await imageId.getAddress(), - blockNumber: await ethers.provider.getBlockNumber(), - }, - 'ImageID', + { address: await verifier.getAddress(), blockNumber: await ethers.provider.getBlockNumber(), constructorArgs: verifierConstructorArgs }, + unprovedTest ? 'MockOpenVmReceiptVerifier' : 'OpenVmReceiptVerifier', chain, ) - - const programId = await imageId.PROGRAM_ID() - const ciphertextVerifier = await ethers.deployContract('Risc0BfvCiphertextVerifier', [await verifier.getAddress(), programId]) + const ciphertextVerifier = await ethers.deployContract('OpenVmBfvCiphertextVerifier', [await verifier.getAddress(), programId]) await ciphertextVerifier.waitForDeployment() const encryptionSchemeId = ethers.keccak256(ethers.toUtf8Bytes('fhe.rs:BFV')) await (await interfold.setCiphertextVerifier(encryptionSchemeId, await ciphertextVerifier.getAddress())).wait() @@ -83,7 +93,7 @@ export const deployTemplate = async () => { console.log( ` Deployed MyProgram at address: ${await e3Program.getAddress()} - Deployed MockRISC0Verifier at address: ${await verifier.getAddress()} + Deployed ${unprovedTest ? 'local unproved test verifier' : 'OpenVmReceiptVerifier'} at address: ${await verifier.getAddress()} `, ) diff --git a/templates/default/eslint.config.js b/templates/default/eslint.config.js index d6df3def7f..facf9ad740 100644 --- a/templates/default/eslint.config.js +++ b/templates/default/eslint.config.js @@ -9,8 +9,6 @@ import config from '@interfold/config/eslint.config.js' export default defineConfig([ globalIgnores([ - // Github submodules. - 'lib/risc0-ethereum', // Build and cache directories. '**/node_modules/**', '**/dist/**', diff --git a/templates/default/hardhat.config.ts b/templates/default/hardhat.config.ts index c8118b485f..89eb98c7f3 100644 --- a/templates/default/hardhat.config.ts +++ b/templates/default/hardhat.config.ts @@ -76,7 +76,7 @@ const config: HardhatUserConfig = { tsNocheck: false, }, paths: { - sources: ['./contracts', './.interfold/generated/contracts'], + sources: ['./contracts'], }, networks: { hardhat: { @@ -136,7 +136,8 @@ const config: HardhatUserConfig = { '@interfold/contracts/contracts/token/InterfoldToken.sol', '@interfold/contracts/contracts/token/InterfoldTicketToken.sol', '@interfold/contracts/contracts/verifiers/bfv/BfvDecryptionVerifier.sol', - '@interfold/contracts/contracts/verifiers/bfv/Risc0BfvCiphertextVerifier.sol', + '@interfold/contracts/contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol', + '@interfold/contracts/contracts/verifiers/OpenVmReceiptVerifier.sol', '@interfold/contracts/contracts/verifiers/bfv/BfvPkVerifier.sol', '@interfold/contracts/contracts/verifiers/bfv/honk/DkgAggregatorVerifier.sol', '@interfold/contracts/contracts/verifiers/bfv/honk/DecryptionAggregatorVerifier.sol', @@ -158,8 +159,10 @@ const config: HardhatUserConfig = { optimizer: { enabled: true, // Low runs shrinks deployment bytecode (EIP-170); higher runs favor runtime gas. - runs: 100, + runs: 1, }, + evmVersion: 'paris', + debug: { revertStrings: 'strip' }, metadata: { bytecodeHash: 'none', }, diff --git a/templates/default/interfold.config.yaml b/templates/default/interfold.config.yaml index f14be5b266..dcc1c66904 100644 --- a/templates/default/interfold.config.yaml +++ b/templates/default/interfold.config.yaml @@ -26,23 +26,10 @@ chains: address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" deploy_block: 16 program: - dev: true - # risc0: - # risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode (fake proofs) - # boundless: - # rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" - # private_key: "PRIVATE_KEY" # Use env vars for secrets - # pinata_jwt: "PINATA_JWT" # For uploading programs - # ipfs_gateway_url: "https://your-gateway.mypinata.cloud" # Public full-download gateway for programs and inputs - # program_url: "https://your-gateway.mypinata.cloud/ipfs/QmNMRAB7DW43JSmENfzGmD96G6sqaeBBNfTVrrq5WQae3D" # Pre-uploaded program - # onchain: true # true = onchain requests, false = offchain - # # Optional auction parameters with their built-in defaults: - # # min_price_eth: 0.00005 - # # max_price_eth: 0.004 - # # timeout_secs: 28800 - # # lock_timeout_secs: 14400 - # # ramp_up_secs: 7200 - # # lock_collateral_zkc: 100.0 + dev: false + # Configure program.openvm.repository, prover_bin, and prover_config with absolute paths. + # The worker must prove this program's policy, not the CRISP reference policy. + # See crates/support/openvm/README.md for the build and deployment requirements. # The scheduler defaults to 2 concurrent jobs and reserves 2 logical CPUs for Actix / libp2p. # It reduces concurrency when the host or cgroup memory limit is too small. # Example override on a dedicated 64 GB host: diff --git a/templates/default/lib/risc0-ethereum b/templates/default/lib/risc0-ethereum deleted file mode 160000 index ef94105fbf..0000000000 --- a/templates/default/lib/risc0-ethereum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ef94105fbfbc2775d7a7f0c4773190e04cb67a04 diff --git a/templates/default/package.json b/templates/default/package.json index 1203695843..45ffe207fc 100644 --- a/templates/default/package.json +++ b/templates/default/package.json @@ -17,7 +17,7 @@ "dev:frontend": "./scripts/dev_frontend.sh", "dev:program": "./scripts/dev_program.sh", "dev:server": "./scripts/dev_server.sh", - "predev:all": "[ ! -f './.interfold/generated/contracts/ImageID.sol' ] && interfold program compile || true", + "predev:all": "interfold program compile", "test": "hardhat test", "test:server": "vitest run ./server/runner.test.ts", "test:integration": "pnpm test:server && ./scripts/test_integration.sh" @@ -46,7 +46,6 @@ "@nomicfoundation/hardhat-verify": "3.0.5", "@openzeppelin/contracts": "5.3.0", "@openzeppelin/contracts-upgradeable": "5.0.2", - "@risc0/ethereum": "file:lib/risc0-ethereum", "@types/chai": "^4.2.0", "@types/express": "^5.0.2", "@types/mocha": ">=9.1.0", diff --git a/templates/default/remappings.txt b/templates/default/remappings.txt index ddc3b1d535..2492677fd8 100644 --- a/templates/default/remappings.txt +++ b/templates/default/remappings.txt @@ -1,4 +1,3 @@ -risc0/=lib/risc0-ethereum/contracts/src/ @interfold/contracts/=node_modules/@interfold/contracts/ @zk-kit/lazy-imt.sol/=node_modules/@zk-kit/lazy-imt.sol/ poseidon-solidity/=node_modules/poseidon-solidity/ diff --git a/templates/default/scripts/dev_ciphernodes.sh b/templates/default/scripts/dev_ciphernodes.sh index ad649d09fe..323a12460a 100755 --- a/templates/default/scripts/dev_ciphernodes.sh +++ b/templates/default/scripts/dev_ciphernodes.sh @@ -26,11 +26,6 @@ trap cleanup INT TERM echo "Waiting for local evm node..." pnpm wait-on tcp:localhost:8545 -if [ ! -f './.interfold/generated/contracts/ImageID.sol' ]; then - echo "Compiling guest program (ImageID)..." - interfold program compile -fi - # Fresh node state for this deploy rm -rf .interfold/data rm -rf .interfold/config diff --git a/templates/default/scripts/setup.sh b/templates/default/scripts/setup.sh index e0ee823620..a2790861ef 100755 --- a/templates/default/scripts/setup.sh +++ b/templates/default/scripts/setup.sh @@ -15,10 +15,8 @@ pnpm install --frozen-lockfile echo "Installing Cargo dependencies..." cargo build -echo "Compiling guest program..." -if [[ ! -f './.interfold/generated/contracts/ImageID.sol' ]]; then - interfold program compile -fi +echo "Compiling the configured program service..." +interfold program compile build_interfold_circuits_at_setup diff --git a/templates/default/scripts/test_integration.sh b/templates/default/scripts/test_integration.sh index 144f5b111b..3d52aec6b9 100755 --- a/templates/default/scripts/test_integration.sh +++ b/templates/default/scripts/test_integration.sh @@ -38,6 +38,8 @@ export E3_NODES__CN2__SKIP_PROOF_AGGREGATION=true export E3_NODES__CN3__SKIP_PROOF_AGGREGATION=true export E3_NODES__CN4__SKIP_PROOF_AGGREGATION=true export E3_NODES__CN5__SKIP_PROOF_AGGREGATION=true +export E3_PROGRAM__DEV=true +export TEMPLATE_UNPROVED_TEST=1 passed_message() { echo "" diff --git a/tests/integration/interfold.config.yaml b/tests/integration/interfold.config.yaml index cee8652bdf..6238fd259e 100644 --- a/tests/integration/interfold.config.yaml +++ b/tests/integration/interfold.config.yaml @@ -29,23 +29,8 @@ chains: deploy_block: 6 program: + # These integration scenarios use an explicitly unproved development program. dev: true - # risc0: - # risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode (fake proofs) - # boundless: - # rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" - # private_key: "PRIVATE_KEY" # Use env vars for secrets - # pinata_jwt: "PINATA_JWT" # For uploading programs - # ipfs_gateway_url: "https://your-gateway.mypinata.cloud" # Public full-download gateway for programs and inputs - # program_url: "https://your-gateway.mypinata.cloud/ipfs/QmNMRAB7DW43JSmENfzGmD96G6sqaeBBNfTVrrq5WQae3D" # Pre-uploaded program - # onchain: true # true = onchain requests, false = offchain - # Optional — custom auction parameters (defaults shown): - # min_price_eth: 0.00005 - # max_price_eth: 0.004 - # timeout_secs: 28800 - # lock_timeout_secs: 14400 - # ramp_up_secs: 7200 - # lock_collateral_zkc: 100.0 # The scheduler defaults to 2 concurrent jobs and reserves 2 logical CPUs for Actix / libp2p. # It reduces concurrency when the host or cgroup memory limit is too small. # Example override on a dedicated 64 GB host: From 564c4e10d4a01ba32148aaba439ea150ea693d83 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 14:00:53 +0500 Subject: [PATCH 02/20] chore!: use upstream fhe.rs zkVM optimizations, drop the FHE patch gnosisguild/fhe.rs#210 merged the two FHE changes that the OpenVM guest applied as a local patch: lazy BFV multiplication tables and canonical power-basis decoding. Pin every fhe.rs dependency to that merge (873dc69, v0.4.1 plus #210) in the root, support, CRISP and template workspaces, and remove the patch, its setup script and the guest's [patch] section. This moves the FHE library for every ciphernode from v0.4.1 to 873dc69. The new code is additive or lazy: parameter construction no longer builds multiplication tables until a multiplication needs them, so a construction error appears at first use. Move the pin to v0.4.2 once it is tagged. --- .gitattributes | 2 - Cargo.lock | 8 +- Cargo.toml | 8 +- crates/support/Cargo.lock | 152 +------ crates/support/Cargo.toml | 6 +- crates/support/openvm/README.md | 8 +- crates/support/openvm/fhe-optimizations.patch | 403 ------------------ crates/support/openvm/guest/Cargo.lock | 181 ++++---- crates/support/openvm/guest/Cargo.toml | 6 - examples/CRISP/Cargo.lock | 8 +- examples/CRISP/Cargo.toml | 8 +- scripts/generate-provenance-manifest.ts | 1 - scripts/run-openvm.sh | 3 +- scripts/setup-openvm-fhe.mjs | 31 -- templates/default/Cargo.lock | 8 +- templates/default/Cargo.toml | 4 +- 16 files changed, 131 insertions(+), 706 deletions(-) delete mode 100644 .gitattributes delete mode 100644 crates/support/openvm/fhe-optimizations.patch delete mode 100644 scripts/setup-openvm-fhe.mjs diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f8be7e3177..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Unified diff context lines can contain a single space. -crates/support/openvm/fhe-optimizations.patch -whitespace diff --git a/Cargo.lock b/Cargo.lock index ac39eb1ee2..ac8ee8c256 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5051,7 +5051,7 @@ dependencies = [ [[package]] name = "fhe" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", @@ -5077,7 +5077,7 @@ dependencies = [ [[package]] name = "fhe-math" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", "fhe-traits", @@ -5101,7 +5101,7 @@ dependencies = [ [[package]] name = "fhe-traits" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "rand 0.9.5", ] @@ -5109,7 +5109,7 @@ dependencies = [ [[package]] name = "fhe-util" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 329fa69e05..fa3a313669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -157,10 +157,10 @@ dirs = "=5.0.1" dialoguer = "=0.11.0" duct = "=1.0.0" eyre = { version = "=0.6.12" } -fhe = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1", features = ["experimental-mbfv"] } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } -fhe-math = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } -fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } +fhe = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a", features = ["experimental-mbfv"] } +fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-math = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } figment = { version = "=0.10.19", features = ["env", "yaml", "test"] } futures = "=0.3.31" futures-util = "=0.3.31" diff --git a/crates/support/Cargo.lock b/crates/support/Cargo.lock index aedeb71480..16aae07937 100644 --- a/crates/support/Cargo.lock +++ b/crates/support/Cargo.lock @@ -221,15 +221,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned-vec" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" -dependencies = [ - "equator", -] - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -1246,8 +1237,8 @@ dependencies = [ "e3-fhe-params", "e3-polynomial", "e3-zk-helpers", - "fhe 0.4.1", - "fhe-traits 0.4.1", + "fhe", + "fhe-traits", "rand 0.9.5", "thiserror 1.0.69", ] @@ -1260,7 +1251,7 @@ dependencies = [ "ark-ff 0.4.2", "e3-bfv-client", "e3-fhe-params", - "fhe 0.4.1", + "fhe", "hex", "lean-imt", "light-poseidon", @@ -1282,7 +1273,7 @@ dependencies = [ "alloy-primitives", "anyhow", "clap", - "fhe 0.4.1", + "fhe", "num-bigint 0.5.1", "num-traits", "rand 0.9.5", @@ -1305,7 +1296,7 @@ dependencies = [ name = "e3-polynomial" version = "0.19.0-test.2" dependencies = [ - "fhe-math 0.4.1", + "fhe-math", "num-bigint 0.5.1", "num-traits", "serde", @@ -1378,8 +1369,8 @@ version = "0.1.0" dependencies = [ "e3-compute-provider", "e3-fhe-params", - "fhe 0.2.1", - "fhe-traits 0.2.1", + "fhe", + "fhe-traits", "openvm-keccak256", "openvm-sha2", "sha2", @@ -1398,9 +1389,9 @@ dependencies = [ "e3-parity-matrix", "e3-polynomial", "e3-safe", - "fhe 0.4.1", - "fhe-math 0.4.1", - "fhe-traits 0.4.1", + "fhe", + "fhe-math", + "fhe-traits", "hex", "itertools 0.14.0", "ndarray", @@ -1518,26 +1509,6 @@ dependencies = [ "log", ] -[[package]] -name = "equator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" -dependencies = [ - "equator-macro", -] - -[[package]] -name = "equator-macro" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1598,42 +1569,16 @@ dependencies = [ "subtle", ] -[[package]] -name = "fhe" -version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" -dependencies = [ - "bincode", - "doc-comment", - "fhe-math 0.2.1", - "fhe-traits 0.2.1", - "fhe-util 0.2.1", - "itertools 0.14.0", - "ndarray", - "num-bigint 0.4.6", - "num-traits", - "prost", - "prost-build", - "rand 0.9.5", - "rand_chacha 0.9.0", - "rand_distr", - "rayon", - "serde", - "thiserror 2.0.21", - "zeroize", - "zeroize_derive", -] - [[package]] name = "fhe" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", - "fhe-math 0.4.1", - "fhe-traits 0.4.1", - "fhe-util 0.4.1", + "fhe-math", + "fhe-traits", + "fhe-util", "itertools 0.15.0", "ndarray", "num-bigint 0.5.1", @@ -1650,39 +1595,14 @@ dependencies = [ "zeroize_derive", ] -[[package]] -name = "fhe-math" -version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" -dependencies = [ - "ethnum", - "fhe-traits 0.2.1", - "fhe-util 0.2.1", - "itertools 0.14.0", - "ndarray", - "num-bigint 0.4.6", - "num-bigint-dig", - "num-traits", - "prost", - "prost-build", - "pulp", - "rand 0.9.5", - "rand_chacha 0.9.0", - "serde", - "sha2", - "tfhe-ntt", - "thiserror 2.0.21", - "zeroize", -] - [[package]] name = "fhe-math" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", - "fhe-traits 0.4.1", - "fhe-util 0.4.1", + "fhe-traits", + "fhe-util", "itertools 0.15.0", "ndarray", "num-bigint 0.5.1", @@ -1699,40 +1619,18 @@ dependencies = [ "zeroize", ] -[[package]] -name = "fhe-traits" -version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" -dependencies = [ - "rand 0.9.5", -] - [[package]] name = "fhe-traits" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "rand 0.9.5", ] -[[package]] -name = "fhe-util" -version = "0.2.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.2.2#f2c1d2258fbeef6dbdf5ade68438203fd80a648e" -dependencies = [ - "num-bigint-dig", - "num-traits", - "prime_factorization", - "rand 0.8.6", - "rand 0.9.5", - "rand_distr", - "rayon", -] - [[package]] name = "fhe-util" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", @@ -2630,7 +2528,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.6", ] [[package]] @@ -3985,17 +3882,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "tfhe-ntt" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10650c743ade46b166c698c8349902ed5986784a7db418c51f810bea25f09e3d" -dependencies = [ - "aligned-vec", - "bytemuck", - "pulp", -] - [[package]] name = "thiserror" version = "1.0.69" diff --git a/crates/support/Cargo.toml b/crates/support/Cargo.toml index 297176eef4..d9f0bc92e3 100644 --- a/crates/support/Cargo.toml +++ b/crates/support/Cargo.toml @@ -35,9 +35,9 @@ serde_json = "=1.0.145" sha2 = "=0.10.9" sha3 = "=0.10.8" # Build this workspace from the repository root to include the guest source dependencies. -fhe = { package = "fhe", git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } -fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.2.2" } +fhe = { package = "fhe", git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } e3-compute-provider = { path = "../compute-provider" } tokio = { version = "=1.46.1", features = ["full"] } rand = { version = "=0.9.2" } diff --git a/crates/support/openvm/README.md b/crates/support/openvm/README.md index 3b74a41d8e..b1abaed75b 100644 --- a/crates/support/openvm/README.md +++ b/crates/support/openvm/README.md @@ -14,7 +14,6 @@ and the correct GPU architecture in the build environment. From the repository root: ```sh -pnpm openvm setup-fhe pnpm openvm guest build pnpm openvm guest keygen --app-only pnpm openvm prover-build --features cuda @@ -24,9 +23,10 @@ pnpm openvm service-build --release Omit `--features cuda` for a CPU worker. The native HTTP service has no SDK or CUDA dependency. The worker is a separate executable so a proof failure does not abort the service process. -The FHE setup checks out a fixed revision and applies the checked-in optimization patch under -`target/openvm/fhe`. It refuses unrelated changes. The optimized guest enables direct coefficient -packing, canonical power-basis decoding, lazy BFV products, modular Poseidon2, SHA-256, and Keccak. +The guest uses fhe.rs at the revision that the workspace pins. That revision includes lazy BFV +multiplication tables and canonical power-basis decoding (gnosisguild/fhe.rs#210), so no local FHE +patch is needed. The optimized guest enables direct coefficient packing, canonical power-basis +decoding, lazy BFV products, modular Poseidon2, SHA-256, and Keccak. The native service uses the same CRISP policy source and compares its journal with the proved output. diff --git a/crates/support/openvm/fhe-optimizations.patch b/crates/support/openvm/fhe-optimizations.patch deleted file mode 100644 index dd63d504c7..0000000000 --- a/crates/support/openvm/fhe-optimizations.patch +++ /dev/null @@ -1,403 +0,0 @@ -diff --git a/crates/fhe-math/Cargo.toml b/crates/fhe-math/Cargo.toml -index 54d9cf8..671d5be 100644 ---- a/crates/fhe-math/Cargo.toml -+++ b/crates/fhe-math/Cargo.toml -@@ -1,4 +1,5 @@ - [package] -+workspace = "../.." - name = "fhe-math" - description = "Mathematical utilities for the fhe.rs library" - authors.workspace = true -diff --git a/crates/fhe-math/src/rq/convert.rs b/crates/fhe-math/src/rq/convert.rs -index bf94490..af20a2a 100644 ---- a/crates/fhe-math/src/rq/convert.rs -+++ b/crates/fhe-math/src/rq/convert.rs -@@ -11,6 +11,7 @@ use crate::{ - use itertools::{Itertools, izip}; - use ndarray::{Array2, ArrayView, Axis}; - use num_bigint::BigUint; -+use prost::Message; - use std::sync::Arc; - use zeroize::{Zeroize, Zeroizing}; - -@@ -106,6 +107,33 @@ impl TryConvertFrom<&Rq> for Poly { - } - } - -+impl Poly { -+ /// Reads canonical power-basis coefficients from an NTT-tagged serialization. -+ /// Returns `None` when the caller must use the standard decoder. -+ pub fn power_basis_from_bytes_if_canonical( -+ bytes: &[u8], -+ ctx: &Arc, -+ ) -> Result>> { -+ let value: Rq = Message::decode(bytes).map_err(|e| Error::Serialization(e.to_string()))?; -+ if value.degree as usize != ctx.degree { -+ return Ok(None); -+ } -+ let (representation, coefficients, variable_time) = parse_proto(&value, ctx, false)?; -+ if representation != Representation::Ntt -+ || coefficients.len() != ctx.moduli.len() * ctx.degree -+ { -+ return Ok(None); -+ } -+ // The standard NTT round trip can reduce noncanonical coefficients. Keep that path. -+ for (row, modulus) in coefficients.chunks_exact(ctx.degree).zip(ctx.moduli.iter()) { -+ if row.iter().any(|coefficient| coefficient >= modulus) { -+ return Ok(None); -+ } -+ } -+ Poly::::try_convert_from(coefficients, ctx, variable_time).map(Some) -+ } -+} -+ - impl TryConvertFrom<&Rq> for Poly { - fn try_convert_from(value: &Rq, ctx: &Arc, variable_time: bool) -> Result { - let (representation_from_proto, coefficients, variable_time) = -diff --git a/crates/fhe-math/src/rq/serialize.rs b/crates/fhe-math/src/rq/serialize.rs -index 45f1460..9f13560 100644 ---- a/crates/fhe-math/src/rq/serialize.rs -+++ b/crates/fhe-math/src/rq/serialize.rs -@@ -43,6 +43,58 @@ mod tests { - 4611686018309947393, - ]; - -+ #[test] -+ fn direct_power_basis_decode_matches_the_ntt_round_trip() -> Result<(), Box> { -+ for degree in [16, 512, 8192] { -+ let ctx = Context::new_arc(Q, degree)?; -+ let values: Vec = Q -+ .iter() -+ .flat_map(|q| { -+ (0..degree).map(move |i| match i % 4 { -+ 0 => 0, -+ 1 => 1, -+ 2 => q / 2, -+ _ => q - 1, -+ }) -+ }) -+ .collect(); -+ let power = Poly::::try_convert_from(values, &ctx, false)?; -+ let ntt = power.clone().into_ntt(); -+ let bytes = ntt.to_bytes(); -+ let direct = Poly::::power_basis_from_bytes_if_canonical(&bytes, &ctx)?.unwrap(); -+ let standard = Poly::::from_bytes(&bytes, &ctx)?.to_power_basis(); -+ assert_eq!(direct, standard); -+ assert_eq!(direct, power); -+ } -+ Ok(()) -+ } -+ -+ #[test] -+ fn direct_power_basis_decode_requires_canonical_coefficients() -> Result<(), Box> { -+ let ctx = Context::new_arc(&Q[..1], 16)?; -+ let poly = Poly::::zero(&ctx); -+ let mut proto = Rq::decode(poly.to_bytes().as_slice())?; -+ proto.coefficients = crate::zq::Modulus::new(Q[0])?.serialize_vec(&vec![Q[0]; 16]); -+ assert!( -+ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? -+ .is_none() -+ ); -+ proto = Rq::decode(poly.to_bytes().as_slice())?; -+ proto.degree = 8; -+ assert!( -+ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? -+ .is_none() -+ ); -+ proto = Rq::decode(poly.to_bytes().as_slice())?; -+ proto.representation = RepresentationProto::Powerbasis as i32; -+ assert!( -+ Poly::::power_basis_from_bytes_if_canonical(&proto.encode_to_vec(), &ctx)? -+ .is_none() -+ ); -+ assert!(Poly::::power_basis_from_bytes_if_canonical(&[255], &ctx).is_err()); -+ Ok(()) -+ } -+ - #[test] - fn serialize() -> Result<(), Box> { - let mut rng = rng(); -diff --git a/crates/fhe-traits/Cargo.toml b/crates/fhe-traits/Cargo.toml -index dba63aa..a1cec02 100644 ---- a/crates/fhe-traits/Cargo.toml -+++ b/crates/fhe-traits/Cargo.toml -@@ -1,4 +1,5 @@ - [package] -+workspace = "../.." - name = "fhe-traits" - description = "Traits for the fhe.rs library" - authors.workspace = true -diff --git a/crates/fhe-util/Cargo.toml b/crates/fhe-util/Cargo.toml -index 72a16dc..a8b1949 100644 ---- a/crates/fhe-util/Cargo.toml -+++ b/crates/fhe-util/Cargo.toml -@@ -1,4 +1,5 @@ - [package] -+workspace = "../.." - name = "fhe-util" - description = "Utilities for the fhe.rs library" - authors.workspace = true -diff --git a/crates/fhe/Cargo.toml b/crates/fhe/Cargo.toml -index a11bd83..b0400d1 100644 ---- a/crates/fhe/Cargo.toml -+++ b/crates/fhe/Cargo.toml -@@ -1,4 +1,5 @@ - [package] -+workspace = "../.." - name = "fhe" - description = "Fully Homomorphic Encryption in Rust" - authors.workspace = true -diff --git a/crates/fhe/src/bfv/ciphertext.rs b/crates/fhe/src/bfv/ciphertext.rs -index 01d4211..c0fbd57 100644 ---- a/crates/fhe/src/bfv/ciphertext.rs -+++ b/crates/fhe/src/bfv/ciphertext.rs -@@ -3,7 +3,7 @@ - use crate::bfv::{parameters::BfvParameters, traits::TryConvertFrom}; - use crate::proto::bfv::Ciphertext as CiphertextProto; - use crate::{Error, Result, SerializationError}; --use fhe_math::rq::{Ntt, Poly}; -+use fhe_math::rq::{Ntt, Poly, PowerBasis}; - use fhe_traits::{ - DeserializeParametrized, DeserializeWithContext, FheCiphertext, FheParametrized, Serialize, - }; -@@ -44,6 +44,33 @@ impl DerefMut for Ciphertext { - } - - impl Ciphertext { -+ /// Reads two canonical level-zero components without an NTT round trip. -+ /// Returns `None` for encodings that require the standard decoder. -+ pub fn power_basis_from_bytes_if_canonical( -+ bytes: &[u8], -+ par: &Arc, -+ ) -> Result>>> { -+ let value: CiphertextProto = Message::decode(bytes).map_err(|_| { -+ Error::SerializationError(SerializationError::ProtobufError { -+ message: "Ciphertext decode".into(), -+ }) -+ })?; -+ if value.level != 0 || !value.seed.is_empty() || value.c.len() != 2 { -+ return Ok(None); -+ } -+ let context = par.context_at_level(0)?; -+ let mut components = Vec::with_capacity(2); -+ for bytes in value.c { -+ let Some(component) = -+ Poly::::power_basis_from_bytes_if_canonical(&bytes, context)? -+ else { -+ return Ok(None); -+ }; -+ components.push(component); -+ } -+ Ok(Some(components)) -+ } -+ - /// Create a ciphertext from a vector of polynomials. - /// A ciphertext must contain at least two polynomials, and all polynomials - /// must be in Ntt representation and with the same context. -diff --git a/crates/fhe/src/bfv/context/chain.rs b/crates/fhe/src/bfv/context/chain.rs -index a07a642..b1a701f 100644 ---- a/crates/fhe/src/bfv/context/chain.rs -+++ b/crates/fhe/src/bfv/context/chain.rs -@@ -5,7 +5,10 @@ use fhe_math::{ - rq::{Context, scaler::Scaler}, - }; - --use crate::bfv::{context::CipherPlainContext, parameters::MultiplicationParameters}; -+use crate::bfv::{ -+ context::CipherPlainContext, -+ parameters::{MultiplicationParameters, MultiplicationParametersSource}, -+}; - - /// A context in the modulus switching chain - #[derive(Debug, Clone)] -@@ -29,6 +32,7 @@ pub struct ContextLevel { - /// Parameters required for ciphertext-ciphertext multiplication at this - /// level - pub(crate) mul_params: OnceLock, -+ pub(crate) mul_params_source: OnceLock>, - } - - impl PartialEq for ContextLevel { -@@ -43,6 +47,7 @@ impl PartialEq for ContextLevel { - down_scaler: _, - up_scaler: _, - mul_params: _, -+ mul_params_source: _, - } = self; - let Self { - poly_context: other_poly_context, -@@ -54,6 +59,7 @@ impl PartialEq for ContextLevel { - down_scaler: _, - up_scaler: _, - mul_params: _, -+ mul_params_source: _, - } = other; - - // OnceCell fields are lazily computed caching fields, not part of equality. -@@ -84,6 +90,7 @@ impl ContextLevel { - down_scaler: OnceLock::new(), - up_scaler: OnceLock::new(), - mul_params: OnceLock::new(), -+ mul_params_source: OnceLock::new(), - } - } - -@@ -134,9 +141,13 @@ impl ContextLevel { - /// Access multiplication parameters for this level - #[expect(clippy::expect_used, reason = "bounds are validated before use")] - pub(crate) fn mul_params(&self) -> &MultiplicationParameters { -- self.mul_params -- .get() -- .expect("multiplication parameters not set") -+ self.mul_params.get_or_init(|| { -+ self.mul_params_source -+ .get() -+ .expect("multiplication parameter source not set") -+ .build(self) -+ .expect("cannot construct multiplication parameters") -+ }) - } - } - -diff --git a/crates/fhe/src/bfv/parameters.rs b/crates/fhe/src/bfv/parameters.rs -index 9b2e770..edad6bc 100644 ---- a/crates/fhe/src/bfv/parameters.rs -+++ b/crates/fhe/src/bfv/parameters.rs -@@ -16,7 +16,7 @@ use num_traits::{PrimInt as _, ToPrimitive}; - use prost::Message; - use std::collections::HashMap; - use std::fmt::Debug; --use std::sync::Arc; -+use std::sync::{Arc, OnceLock}; - - /// Enum to support both small (u64) and large (BigUint) plaintext moduli. - #[derive(Debug, PartialEq, Eq, Clone)] -@@ -689,33 +689,17 @@ impl BfvParametersBuilder { - } - let context_chain = nodes.first().unwrap().clone(); - -- // Create n+1 moduli of 62 bits for multiplication. -- let mut extended_basis = Vec::with_capacity(moduli.len() + 1); -- let mut upper_bound = 1 << 62; -- while extended_basis.len() != moduli.len() + 1 { -- upper_bound = generate_prime(62, 2 * self.degree as u64, upper_bound).unwrap(); -- if !extended_basis.contains(&upper_bound) && !moduli.contains(&upper_bound) { -- extended_basis.push(upper_bound) -- } -- } -- -- // Compute multiplication parameters for each level -- for (i, node) in nodes.iter().enumerate() { -- // For the first multiplication, we want to extend to a context that -- // is ~60 bits larger. -- let modulus_size = moduli_sizes[..moduli_sizes.len() - i].iter().sum::(); -- let n_moduli = (modulus_size + 60).div_ceil(62); -- let mut mul_1_moduli = vec![]; -- mul_1_moduli.append(&mut moduli[..moduli_sizes.len() - i].to_vec()); -- mul_1_moduli.append(&mut extended_basis[..n_moduli].to_vec()); -- let mul_1_ctx = Context::new_arc(&mul_1_moduli, self.degree)?; -- let mp = MultiplicationParameters::new( -- &node.poly_context, -- &mul_1_ctx, -- ScalingFactor::one(), -- ScalingFactor::new(plaintext_big, node.poly_context.modulus()), -- )?; -- node.mul_params.set(mp).unwrap(); -+ // Addition does not need the extended multiplication basis or its NTT tables. -+ let mul_params_source = Arc::new(MultiplicationParametersSource { -+ moduli: moduli.clone(), -+ plaintext: plaintext_big.clone(), -+ degree: self.degree, -+ extended_basis: OnceLock::new(), -+ }); -+ for node in &nodes { -+ node.mul_params_source -+ .set(mul_params_source.clone()) -+ .unwrap(); - } - - // We use the same code as SEAL -@@ -799,6 +783,46 @@ impl Deserialize for BfvParameters { - type Error = Error; - } - -+/// Immutable inputs used to construct multiplication tables on first use. -+#[derive(Debug)] -+pub(crate) struct MultiplicationParametersSource { -+ moduli: Vec, -+ plaintext: BigUint, -+ degree: usize, -+ extended_basis: OnceLock>, -+} -+ -+impl MultiplicationParametersSource { -+ pub(crate) fn build(&self, node: &ContextLevel) -> Result { -+ let extended_basis = self.extended_basis.get_or_init(|| { -+ let mut basis = Vec::with_capacity(self.moduli.len() + 1); -+ let mut upper_bound = 1 << 62; -+ while basis.len() != self.moduli.len() + 1 { -+ upper_bound = generate_prime(62, 2 * self.degree as u64, upper_bound).unwrap(); -+ if !basis.contains(&upper_bound) && !self.moduli.contains(&upper_bound) { -+ basis.push(upper_bound); -+ } -+ } -+ basis -+ }); -+ let level_moduli = node.poly_context.moduli(); -+ let modulus_size = level_moduli -+ .iter() -+ .map(|m| 64 - m.leading_zeros() as usize) -+ .sum::(); -+ let n_moduli = (modulus_size + 60).div_ceil(62); -+ let mut mul_moduli = level_moduli.to_vec(); -+ mul_moduli.extend_from_slice(&extended_basis[..n_moduli]); -+ let mul_context = Context::new_arc(&mul_moduli, self.degree)?; -+ MultiplicationParameters::new( -+ &node.poly_context, -+ &mul_context, -+ ScalingFactor::one(), -+ ScalingFactor::new(&self.plaintext, node.poly_context.modulus()), -+ ) -+ } -+} -+ - /// Multiplication parameters - #[derive(Debug, Clone, PartialEq, Eq, Default)] - pub(crate) struct MultiplicationParameters { -@@ -833,6 +857,36 @@ mod tests { - use prost::Message; - use std::error::Error; - -+ #[test] -+ fn multiplication_tables_are_lazy_and_do_not_change_serialization() { -+ let params = BfvParametersBuilder::new() -+ .set_degree(16) -+ .set_plaintext_modulus(1153) -+ .set_moduli_sizes(&[50, 50]) -+ .build() -+ .unwrap(); -+ let bytes = params.to_bytes(); -+ let head = params.context_chain(); -+ for node in head.iter_chain() { -+ assert!(node.mul_params.get().is_none()); -+ assert!( -+ node.mul_params_source -+ .get() -+ .unwrap() -+ .extended_basis -+ .get() -+ .is_none() -+ ); -+ } -+ let first = head.mul_params() as *const _; -+ assert_eq!(first, head.mul_params() as *const _); -+ assert!(head.next.get().unwrap().mul_params.get().is_none()); -+ assert_eq!(params.to_bytes(), bytes); -+ assert_eq!(params, BfvParameters::try_deserialize(&bytes).unwrap()); -+ let source = head.mul_params_source.get().unwrap(); -+ assert_eq!(head.mul_params(), &source.build(&head).unwrap()); -+ } -+ - #[test] - fn default() { - let params = BfvParameters::default_arc(1, 16); diff --git a/crates/support/openvm/guest/Cargo.lock b/crates/support/openvm/guest/Cargo.lock index 4abbaf18b8..1e70c8fe30 100644 --- a/crates/support/openvm/guest/Cargo.lock +++ b/crates/support/openvm/guest/Cargo.lock @@ -23,15 +23,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned-vec" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" -dependencies = [ - "equator", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -85,7 +76,7 @@ dependencies = [ "keccak-asm", "paste", "proptest", - "rand 0.9.2", + "rand 0.9.5", "ruint", "rustc-hash", "serde", @@ -292,7 +283,7 @@ dependencies = [ "fnv", "hashbrown 0.15.5", "itertools 0.13.0", - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", "zeroize", @@ -309,7 +300,7 @@ dependencies = [ "ark-serialize 0.3.0", "ark-std 0.3.0", "derivative", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version 0.3.3", @@ -329,7 +320,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version 0.4.1", @@ -350,7 +341,7 @@ dependencies = [ "digest 0.10.7", "educe", "itertools 0.13.0", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "paste", "zeroize", @@ -368,7 +359,7 @@ dependencies = [ "ark-std 0.6.0", "digest 0.10.7", "educe", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "zeroize", ] @@ -419,7 +410,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "quote", "syn 1.0.109", @@ -431,7 +422,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -444,7 +435,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -457,7 +448,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -511,7 +502,7 @@ dependencies = [ "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", ] [[package]] @@ -524,7 +515,7 @@ dependencies = [ "ark-std 0.5.0", "arrayvec", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", ] [[package]] @@ -536,7 +527,7 @@ dependencies = [ "ark-serialize-derive 0.6.0", "ark-std 0.6.0", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.6", "serde_with", ] @@ -1117,7 +1108,7 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "e3-bfv-client" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "anyhow", "e3-fhe-params", @@ -1125,13 +1116,13 @@ dependencies = [ "e3-zk-helpers", "fhe", "fhe-traits", - "rand 0.9.2", + "rand 0.9.5", "thiserror 1.0.69", ] [[package]] name = "e3-compute-provider" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -1141,7 +1132,7 @@ dependencies = [ "hex", "lean-imt", "light-poseidon", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "openvm-keccak256", "serde", @@ -1153,16 +1144,16 @@ dependencies = [ [[package]] name = "e3-fhe-params" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "alloy-dyn-abi", "alloy-primitives", "anyhow", "clap", "fhe", - "num-bigint", + "num-bigint 0.5.1", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "serde", "thiserror 1.0.69", @@ -1170,9 +1161,9 @@ dependencies = [ [[package]] name = "e3-parity-matrix" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ - "num-bigint", + "num-bigint 0.5.1", "num-traits", "serde", "thiserror 1.0.69", @@ -1180,10 +1171,10 @@ dependencies = [ [[package]] name = "e3-polynomial" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "fhe-math", - "num-bigint", + "num-bigint 0.5.1", "num-traits", "serde", "thiserror 1.0.69", @@ -1191,12 +1182,12 @@ dependencies = [ [[package]] name = "e3-safe" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "num-bigint", + "num-bigint 0.4.6", "openvm", "openvm-algebra-guest", "serde", @@ -1233,7 +1224,7 @@ dependencies = [ [[package]] name = "e3-zk-helpers" -version = "0.15.2" +version = "0.19.0-test.2" dependencies = [ "anyhow", "ark-bn254 0.5.0", @@ -1249,10 +1240,10 @@ dependencies = [ "hex", "itertools 0.14.0", "ndarray", - "num-bigint", + "num-bigint 0.5.1", "num-integer", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rayon", "serde", "serde_json", @@ -1343,26 +1334,6 @@ dependencies = [ "syn 3.0.6", ] -[[package]] -name = "equator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" -dependencies = [ - "equator-macro", -] - -[[package]] -name = "equator-macro" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1425,20 +1396,21 @@ dependencies = [ [[package]] name = "fhe" -version = "0.2.1" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", "fhe-math", "fhe-traits", "fhe-util", - "itertools 0.14.0", + "itertools 0.15.0", "ndarray", - "num-bigint", + "num-bigint 0.5.1", "num-traits", "prost", "prost-build", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_distr", "rayon", @@ -1450,44 +1422,45 @@ dependencies = [ [[package]] name = "fhe-math" -version = "0.2.1" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", "fhe-traits", "fhe-util", - "itertools 0.14.0", + "itertools 0.15.0", "ndarray", - "num-bigint", + "num-bigint 0.5.1", "num-bigint-dig", "num-traits", "prost", "prost-build", "pulp", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "serde", "sha2", - "tfhe-ntt", "thiserror 2.0.20", "zeroize", ] [[package]] name = "fhe-traits" -version = "0.2.1" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ - "rand 0.9.2", + "rand 0.9.5", ] [[package]] name = "fhe-util" -version = "0.2.1" +version = "0.4.1" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", "prime_factorization", - "rand 0.8.8", - "rand 0.9.2", + "rand 0.9.5", "rand_distr", "rayon", ] @@ -1808,6 +1781,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1965,7 +1947,7 @@ checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", - "num-bigint", + "num-bigint 0.4.6", "thiserror 1.0.69", ] @@ -2051,7 +2033,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -2068,6 +2050,18 @@ dependencies = [ "num-integer", "num-traits", "rand 0.8.8", +] + +[[package]] +name = "num-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.9.5", + "rand_core 0.9.5", "serde", ] @@ -2082,7 +2076,7 @@ dependencies = [ "num-iter", "num-traits", "once_cell", - "rand 0.9.2", + "rand 0.9.5", "serde", "smallvec", ] @@ -2128,7 +2122,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -2142,7 +2136,7 @@ dependencies = [ "bitvec", "either", "lru", - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-modular", "num-traits", @@ -2155,7 +2149,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -2190,7 +2184,7 @@ dependencies = [ "bytemuck", "getrandom 0.2.17", "getrandom 0.3.4", - "num-bigint", + "num-bigint 0.4.6", "openvm-custom-insn", "openvm-platform", "openvm-rv32im-guest", @@ -2212,7 +2206,7 @@ name = "openvm-algebra-guest" version = "2.0.2" source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "once_cell", "openvm-algebra-complex-macros", "openvm-algebra-moduli-macros", @@ -2227,7 +2221,7 @@ name = "openvm-algebra-moduli-macros" version = "2.0.2" source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-prime", "openvm-macros-common", "quote", @@ -2491,7 +2485,7 @@ dependencies = [ "bit-vec", "bitflags 2.13.2", "num-traits", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -2620,9 +2614,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -2675,7 +2669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" dependencies = [ "num-traits", - "rand 0.9.2", + "rand 0.9.5", ] [[package]] @@ -2823,14 +2817,14 @@ dependencies = [ "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", "parity-scale-codec", "primitive-types", "proptest", "rand 0.8.8", - "rand 0.9.2", + "rand 0.9.5", "rlp", "ruint-macro", "serde_core", @@ -3224,7 +3218,7 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "ark-std 0.5.0", - "num-bigint", + "num-bigint 0.4.6", "num-traits", ] @@ -3247,17 +3241,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "tfhe-ntt" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10650c743ade46b166c698c8349902ed5986784a7db418c51f810bea25f09e3d" -dependencies = [ - "aligned-vec", - "bytemuck", - "pulp", -] - [[package]] name = "thiserror" version = "1.0.69" diff --git a/crates/support/openvm/guest/Cargo.toml b/crates/support/openvm/guest/Cargo.toml index 1bc3671a20..bceef9ffad 100644 --- a/crates/support/openvm/guest/Cargo.toml +++ b/crates/support/openvm/guest/Cargo.toml @@ -18,12 +18,6 @@ e3-safe = { path = "../../../safe", features = ["openvm"] } bincode = "=1.3.3" sha2 = "=0.10.9" -[patch."https://github.com/gnosisguild/fhe.rs"] -fhe = { path = "../../../../target/openvm/fhe/crates/fhe" } -fhe-math = { path = "../../../../target/openvm/fhe/crates/fhe-math" } -fhe-traits = { path = "../../../../target/openvm/fhe/crates/fhe-traits" } -fhe-util = { path = "../../../../target/openvm/fhe/crates/fhe-util" } - [profile.release] lto = "fat" codegen-units = 1 diff --git a/examples/CRISP/Cargo.lock b/examples/CRISP/Cargo.lock index 78cd1ee785..8beb770f02 100644 --- a/examples/CRISP/Cargo.lock +++ b/examples/CRISP/Cargo.lock @@ -3396,7 +3396,7 @@ dependencies = [ [[package]] name = "fhe" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", @@ -3422,7 +3422,7 @@ dependencies = [ [[package]] name = "fhe-math" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", "fhe-traits", @@ -3446,7 +3446,7 @@ dependencies = [ [[package]] name = "fhe-traits" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "rand 0.9.5", ] @@ -3454,7 +3454,7 @@ dependencies = [ [[package]] name = "fhe-util" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", diff --git a/examples/CRISP/Cargo.toml b/examples/CRISP/Cargo.toml index 1d06ccadc4..8c268c5d9f 100644 --- a/examples/CRISP/Cargo.toml +++ b/examples/CRISP/Cargo.toml @@ -49,10 +49,10 @@ log = { version = "=0.4.27" } reqwest = { version = "=0.12.22", features = ["json"] } serde = { version = "=1.0.228", features = ["derive", "std"] } serde_json = "=1.0.145" -fhe = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1", features = ["experimental-mbfv"] } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } -fhe-math = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } -fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } +fhe = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a", features = ["experimental-mbfv"] } +fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-math = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } +fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } tokio = { version = "=1.46.1", features = ["full"] } rand = { version = "0.9" } tracing = { version = "=0.1.41" } diff --git a/scripts/generate-provenance-manifest.ts b/scripts/generate-provenance-manifest.ts index 64d5fb6cac..7f0217d90e 100644 --- a/scripts/generate-provenance-manifest.ts +++ b/scripts/generate-provenance-manifest.ts @@ -69,7 +69,6 @@ async function main() { 'crates/support/openvm/prover/Cargo.lock', 'rust-toolchain.toml', 'crates/support/openvm/guest/openvm.toml', - 'crates/support/openvm/fhe-optimizations.patch', ] const sourceDigests = Object.fromEntries(await Promise.all(files.map(async (file) => [file, await digest(path.join(root, file))]))) const sourceCommit = command('git', ['rev-parse', 'HEAD']) diff --git a/scripts/run-openvm.sh b/scripts/run-openvm.sh index 23c455001a..302709084f 100644 --- a/scripts/run-openvm.sh +++ b/scripts/run-openvm.sh @@ -5,7 +5,6 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" command="${1:-}" shift || true case "$command" in - setup-fhe) exec node "$ROOT/scripts/setup-openvm-fhe.mjs" "$@" ;; cli-build) exec cargo build --locked --release --manifest-path "$ROOT/Cargo.toml" -p e3-cli --bin interfold "$@" ;; @@ -51,5 +50,5 @@ case "$command" in service-e2e) OPENVM_E2E_ENABLED=1 exec pnpm --filter @crisp-e3/contracts test --network localhost tests/openvm-service.test.ts "$@" ;; - *) echo 'Usage: pnpm openvm setup-fhe|cli-build|fixture|crisp-server-build|crisp-server-test|service-build|service-test|service-check|service-start|prover-build|prover-test|prover-check|prover|guest|contract-test|proof-test|service-e2e [arguments]' >&2; exit 2 ;; + *) echo 'Usage: pnpm openvm cli-build|fixture|crisp-server-build|crisp-server-test|service-build|service-test|service-check|service-start|prover-build|prover-test|prover-check|prover|guest|contract-test|proof-test|service-e2e [arguments]' >&2; exit 2 ;; esac diff --git a/scripts/setup-openvm-fhe.mjs b/scripts/setup-openvm-fhe.mjs deleted file mode 100644 index 0b95b424d6..0000000000 --- a/scripts/setup-openvm-fhe.mjs +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -import { spawnSync } from 'node:child_process' -import { existsSync, mkdirSync, readFileSync } from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' - -const root = fileURLToPath(new URL('../', import.meta.url)) -const destination = path.join(root, 'target/openvm/fhe') -const revision = 'f2c1d2258fbeef6dbdf5ade68438203fd80a648e' -const patch = path.join(root, 'crates/support/openvm/fhe-optimizations.patch') -function git(args, cwd = destination) { - const result = spawnSync('git', args, { cwd, encoding: 'utf8' }) - if (result.error || result.status !== 0) throw result.error ?? new Error(result.stderr) - return result.stdout.trimEnd() -} -if (!existsSync(destination)) { - mkdirSync(path.dirname(destination), { recursive: true }) - git(['clone', '--filter=blob:none', '--no-checkout', 'https://github.com/gnosisguild/fhe.rs.git', destination], root) - git(['checkout', '--detach', revision]) -} -if (git(['rev-parse', 'HEAD']) !== revision) throw new Error(`The FHE checkout must use revision ${revision}`) -const expected = readFileSync(patch, 'utf8').trimEnd() -const actual = git(['diff', 'HEAD']) -if (actual && actual !== expected) throw new Error('The FHE checkout contains changes that differ from the OpenVM patch') -if (!actual) { - git(['apply', '--check', patch]) - git(['apply', patch]) -} -if (git(['diff', 'HEAD']) !== expected) throw new Error('The applied FHE patch does not match the OpenVM patch') -console.log(`FHE ${revision}: OpenVM patch verified`) diff --git a/templates/default/Cargo.lock b/templates/default/Cargo.lock index eb0ad49e68..6456f62fd7 100644 --- a/templates/default/Cargo.lock +++ b/templates/default/Cargo.lock @@ -1579,7 +1579,7 @@ dependencies = [ [[package]] name = "fhe" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", @@ -1605,7 +1605,7 @@ dependencies = [ [[package]] name = "fhe-math" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", "fhe-traits", @@ -1629,7 +1629,7 @@ dependencies = [ [[package]] name = "fhe-traits" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "rand 0.9.5", ] @@ -1637,7 +1637,7 @@ dependencies = [ [[package]] name = "fhe-util" version = "0.4.1" -source = "git+https://github.com/gnosisguild/fhe.rs?tag=v0.4.1#7a357b60e33820c27ddf4e43a3ebf2615f330836" +source = "git+https://github.com/gnosisguild/fhe.rs?rev=873dc69c07eae251f88c4b5cacf6c4453e2c365a#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", diff --git a/templates/default/Cargo.toml b/templates/default/Cargo.toml index 0375cb53b6..16a0280ddf 100644 --- a/templates/default/Cargo.toml +++ b/templates/default/Cargo.toml @@ -7,8 +7,8 @@ members = [ [workspace.dependencies] e3-user-program = { path = "./program" } -fhe = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1", features = ["experimental-mbfv"] } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.1" } +fhe = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a", features = ["experimental-mbfv"] } +fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } e3-program-server = { path = "../../crates/program-server" } e3-bfv-client = { path = "../../crates/bfv-client" } e3-fhe-params = { path = "../../crates/fhe-params" } From aff569bb67458de7ffff8accc07a9c3d3287c2f6 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 14:15:53 +0500 Subject: [PATCH 03/20] chore: satisfy clippy in the coefficient packing and CRISP leaf code --- crates/zk-helpers/src/packing.rs | 4 ++-- examples/CRISP/program/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/zk-helpers/src/packing.rs b/crates/zk-helpers/src/packing.rs index 3d8d43bacd..6d0ee4ec62 100644 --- a/crates/zk-helpers/src/packing.rs +++ b/crates/zk-helpers/src/packing.rs @@ -177,7 +177,7 @@ pub fn pack_centered_rns_row(coefficients: &[u64], modulus: u64, bit: u32) -> Op let mut accumulator = FieldInteger::<4>::from(0u64); for _ in 0..group { let value = values.next().copied().unwrap_or(0); - let negative = if modulus % 2 == 0 { + let negative = if modulus.is_multiple_of(2) { value >= modulus / 2 } else { value > modulus / 2 @@ -236,7 +236,7 @@ mod tests { for bit in [0, 1, 4, 5, 8, 31, 32, 51, 53, 60, 64, 100, 120] { let (nibble_bits, group) = packing_layout(bit); let base = BigInt::from(1) << nibble_bits; - let edge = vec![ + let edge = [ -&base, -&base + 1, BigInt::from(-1), diff --git a/examples/CRISP/program/src/lib.rs b/examples/CRISP/program/src/lib.rs index 58a8c1c8dc..bf4868600c 100644 --- a/examples/CRISP/program/src/lib.rs +++ b/examples/CRISP/program/src/lib.rs @@ -100,7 +100,7 @@ pub mod policy { metadata_of(input)?; let mut outer = Sha256::new(); - outer.update(&keccak256(input.ciphertext)); + outer.update(keccak256(input.ciphertext)); outer.update(commitment); outer.update(input.metadata); Ok(leaf_from_digest(&outer.finalize())) From 616080cbf00f8d362d0cb63c98f018195c69c903 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 16:35:44 +0500 Subject: [PATCH 04/20] fix: restore local CRISP runs and init, and correct OpenVM tooling - Remove the `ctl` support links in the template and CRISP. They pointed to the deleted RISC Zero launch scripts, so `interfold init` failed to copy the template. - CRISP local development and the end-to-end test run the unproved development runner against a verifier that accepts every receipt (`CRISP_UNPROVED_TEST`, chain 31337 only). `CRISP_REAL_PROOFS=1` selects the configured OpenVM worker and the real verifier. - A config that still has `program.risc0` loads again, so ciphernodes that share the file keep starting; `interfold program` refuses it with a migration message. - The live OpenVM service test registers the secure parameter set at index 2. - The CRISP governance builder no longer sends mainnet operators to the RISC Zero activation. - The manifest and address checks know the OpenVM verifiers. - `update_revs.sh` rewrites only Interfold revisions, not the fhe.rs pin. - Correct stale RISC Zero comments, ignore entries and receipt-identity NatSpec. --- .github/workflows/ci.yml | 5 ++- .github/workflows/releases.yml | 6 ++-- .gitignore | 4 +-- .prettierignore | 3 -- agent/flow-trace/00_INDEX.md | 2 +- agent/flow-trace/07_UPGRADES.md | 6 ++-- crates/config/src/program_config.rs | 33 +++++++++++++++++++ crates/scripts/update_revs.sh | 5 +-- crates/support-scripts/src/lib.rs | 2 ++ crates/support/.dockerignore | 1 - examples/CRISP/.gitignore | 2 -- examples/CRISP/.interfold/support/ctl | 1 - examples/CRISP/Readme.md | 10 +++--- examples/CRISP/crisp.dev.env.example | 6 ++++ .../contracts/CRISPProgram.sol | 13 ++++---- .../test/MockOpenVmReceiptVerifier.sol | 14 ++++++++ .../deploy/create-governance-builder.ts | 2 +- .../packages/crisp-contracts/deploy/crisp.ts | 18 +++++++++- .../tests/openvm-service.test.ts | 8 +++-- examples/CRISP/scripts/lib/dev_config.sh | 13 +++++++- .../contracts/lib/Risc0ComputeProof.sol | 3 +- .../scripts/genManifest.ts | 3 ++ scripts/README.md | 4 +-- scripts/check-addresses.ts | 3 ++ templates/default/.interfold/support/ctl | 1 - templates/default/contracts/MyProgram.sol | 3 +- 26 files changed, 129 insertions(+), 42 deletions(-) delete mode 120000 examples/CRISP/.interfold/support/ctl create mode 100644 examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmReceiptVerifier.sol delete mode 120000 templates/default/.interfold/support/ctl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1ce2fe2b3..6318162c3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -415,9 +415,8 @@ jobs: # `parallel` is off by default, so the library tests compile the sequential fallback of # `recompute_commitments` and the rayon body of that function ships untested. This step is # what exercises it. Scoped with `-p` rather than `--all-features`: the feature is the one - # thing this crate needs enabled, and the zkVM guest is unaffected either way because it - # builds from `crates/support/methods/guest`, which takes this crate by git revision with - # default features. + # thing this crate needs enabled, and the OpenVM guest is unaffected either way because it + # builds this crate without the feature. - name: Run compute-provider Unit Tests with parallel batching if: matrix.suite == 'doc' run: 'cargo test -p e3-compute-provider --features parallel' diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 254f7122ac..a069cc5fc4 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -384,9 +384,9 @@ jobs: node-version: '22' # The compute-provider provenance manifest is NOT generated here: it can only be complete on - # a machine that built the guest (Elf.sol + builder image digest) with a deployed ciphertext - # verifier to read (--rpc/--verifier), none of which this job has. It is produced manually per - # docs/pages/build/e3-program/verify-compute-provider.mdx until the guest-build job can attach it. + # a machine that built the OpenVM guest and its keys and can check a deployed receipt verifier + # (--rpc/--verifier), none of which this job has. It is produced manually per + # docs/pages/build/e3-program/verify-compute-provider.mdx until a guest-build job can attach it. - name: Prepare release assets and notes env: diff --git a/.gitignore b/.gitignore index d51aabb1fa..66491818ae 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,8 @@ openvm-prover.local.json # agent working files .hermes/ -# Local secrets. `crates/support/.env` holds the Boundless RPC URL, wallet key and Pinata JWT that -# `boundless_prove_inner` reads from the environment. Committing one publishes a funded key. +# Local secrets. `crates/support/.env` can hold deployment keys and machine-specific paths. +# Committing one publishes them. # The agent permission files deny reads of these paths, but a denied read does not stop `git add`, # so the per-environment variants are ignored here too. .env diff --git a/.prettierignore b/.prettierignore index ffc993ae7e..efb1036b9c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -40,9 +40,6 @@ test-results/ **/example.secrets.json **/*.secrets.json -# submodules -examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum -templates/default/lib/risc0-ethereum .claude/ .claude/settings.local.json \ No newline at end of file diff --git a/agent/flow-trace/00_INDEX.md b/agent/flow-trace/00_INDEX.md index d1cfda99dd..40251c654a 100644 --- a/agent/flow-trace/00_INDEX.md +++ b/agent/flow-trace/00_INDEX.md @@ -611,7 +611,7 @@ rows: a `Resolved` row describes this repository's remediation, not an auditor's | ZEN2-07 | Registry-wide randomness breaker and unreserved VRF | Low | Resolved | An expired randomness response no longer clears the registry-global provider. It sets an advisory `degraded` flag and emits `RandomnessCircuitBreakerTripped`; governance re-points the provider. `ChainlinkVrfRandomnessProvider` also counts unfulfilled draws and requires `balance >= minimum * (pending + 1)`. | | ZEN2-08 | **VectorX pointer rotation bricks in-flight rounds (Zenith #8)** | Low | Documented | `AvailVectorXDataAvailabilityVerifier` re-checks `bridge.vectorx() == vectorx` on every call and fails closed on a rotation. Data availability binds per program, so only programs on the rotated pair are affected and `unregisterE3Program` contains new requests without a protocol-wide pause. Neither remedy the auditor proposed is implemented: a governed re-point would split a round's inputs across two providers, and the persisted `DataReference` carries no provider identifier, so the earlier retrieval coordinates become unresolvable and the aggregate step cannot read the round; a deadline extension cannot move the payer, because `FailurePayerLib` reads only the failure reason, which follows the stalled stage. In-flight rounds of an affected program are lost at the compute deadline. Detection, containment, and recovery are in `flow-trace/08`. | | ZEN2-09 | **Committee release inside the accusation window (Zenith #9)** | Medium | Resolved | `releaseCommittee` on a finalized committee also requires `block.timestamp > SlashingManager.accusationSubmissionDeadline(e3Id)`. A member of an early-ended round cannot release its committee obligation and claim a matured exit while a valid accusation can still be filed. Unfinalized committees still release at terminal stage. `closeE3` clears the deadline only after it passed, so 0 also permits release. | -| ZEN2-10 | **Tracked CRISP image id copy is obsolete (Zenith #10)** | Info | Resolved | `examples/CRISP/.interfold/generated/contracts/ImageID.sol` held a pre-PR-1915 `PROGRAM_ID` while the canonical `crates/support/contracts/ImageID.sol` moved on. No consumer reads the copy: `crisp.ts` and `secureCrispArtifacts.ts` both read the canonical file, and the template scripts regenerate their own copy when it is absent. The copy is now untracked and `.interfold/generated/` is ignored, so the duplicate cannot go stale again. The guest was not rebuilt and no constant was hand-edited. | +| ZEN2-10 | **Tracked CRISP image id copy is obsolete (Zenith #10)** | Info | Resolved | `examples/CRISP/.interfold/generated/contracts/ImageID.sol` held a pre-PR-1915 `PROGRAM_ID` while the canonical `crates/support/contracts/ImageID.sol` moved on. No consumer reads the copy: `secureCrispArtifacts.ts` reads the canonical file for the historical RISC Zero activation. Since the OpenVM migration, `crisp.ts` and the template read the receipt identity from the deployed `OpenVmReceiptVerifier` instead, and no script regenerates an `ImageID.sol` copy. The copy is now untracked and `.interfold/generated/` is ignored, so the duplicate cannot go stale again. The guest was not rebuilt and no constant was hand-edited. | | ZEN2-11 | **Cached invalid availability proof blocks recovery (Zenith #11)** | Low | Resolved | `JobState::Ready` now keeps the `PendingPublication` beside the candidate proof, so a proof that Ethereum refuses returns to `AwaitingProof` and asks the bridge for a replacement for bytes Avail already holds. No second publication is paid. The field is `Option` with `serde(default)`, so a record written before this change still decodes and keeps its candidate; such a job needs operator recovery. | | ZEN2-12 | **Owner could initialize CRISP state for another program's E3** | Informational | Resolved | `CRISPProgram.validate` requires `e3.e3Program == address(this)` before it records round state, and `_keyPublishedE3` repeats the check as defense in depth. Interfold stores the provisional E3 and its selected program before it calls `validate`, so the assignment is readable at initialization. | | ZEN2-13 | **Tree capacity one leaf above the reachable maximum** | Informational | Resolved | `CiphernodeRegistryOwnable.MAX_CIPHERNODE_LEAVES` is `2**TREE_DEPTH - 1`. The pinned LazyIMT sets `maxIndex = (1 << depth) - 1` and inserts only while `index < maxIndex`, so the previous cap let the last append pass the registry check and revert inside the dependency. | diff --git a/agent/flow-trace/07_UPGRADES.md b/agent/flow-trace/07_UPGRADES.md index dc91d29216..a876f17970 100644 --- a/agent/flow-trace/07_UPGRADES.md +++ b/agent/flow-trace/07_UPGRADES.md @@ -25,9 +25,9 @@ change the DKG and proof inputs. Its non-centered plaintext scale also changes t check and its circuit artifacts. Drain active E3s and install matching circuit artifacts and verifier routes before requests resume. Both parameter sets use the circuit ID domain `interfold-bfv-v4`. Old clients must update their expected configuration IDs before they submit new -requests. The RISC Zero guest in `crates/support` uses a separate, content-addressed Interfold -revision. Rebuild its image and provenance record before changing that guest revision or its fhe.rs -pin. +requests. The OpenVM guest builds from the same tree. A change to its sources or its fhe.rs pin +changes its application commitments, so rebuild the guest, regenerate its keys and provenance +record, and deploy matching receipt verifiers before such a change serves a live program. The mainnet `paramSetRegistry(1)` contains the previous secure parameters and cannot be changed. Version 7 uses parameter-set index 2 for the new secure tuple. Keep index 1 intact for old E3 diff --git a/crates/config/src/program_config.rs b/crates/config/src/program_config.rs index e6779aab57..11a0ebb4ec 100644 --- a/crates/config/src/program_config.rs +++ b/crates/config/src/program_config.rs @@ -24,6 +24,11 @@ pub struct OpenVmConfig { pub struct ProgramConfig { openvm: Option, dev: Option, + /// The removed RISC Zero and Boundless settings. A config that still has them loads, so that a + /// ciphernode sharing the file keeps starting after the upgrade; `interfold program` refuses + /// them (see [`ProgramConfig::ensure_supported`]). + #[serde(default, rename = "risc0", skip_serializing)] + legacy_risc0: Option, } impl ProgramConfig { @@ -34,6 +39,17 @@ impl ProgramConfig { pub fn dev(&self) -> bool { self.dev.unwrap_or(false) } + + /// Refuse the removed `program.risc0` section, which no program backend reads any more. + pub fn ensure_supported(&self) -> anyhow::Result<()> { + anyhow::ensure!( + self.legacy_risc0.is_none(), + "program.risc0 is no longer supported: OpenVM replaced RISC Zero and Boundless. \ + Remove program.risc0 and configure program.openvm, or set program.dev for unproved \ + local runs" + ); + Ok(()) + } } #[cfg(test)] @@ -65,6 +81,23 @@ openvm: assert!(serde_yaml::from_str::("unknown_backend: {}").is_err()); } + /// A config written for the RISC Zero backend still loads, so a ciphernode that shares the file + /// keeps starting, but no program command accepts it. + #[test] + fn loads_the_removed_risc0_section_and_refuses_it_for_programs() { + let config: ProgramConfig = serde_yaml::from_str( + r#" +risc0: + risc0_dev_mode: 0 + boundless: + rpc_url: "https://base.example" +"#, + ) + .expect("a config with the removed section must still load"); + assert!(config.ensure_supported().is_err()); + assert!(ProgramConfig::default().ensure_supported().is_ok()); + } + #[test] fn development_execution_requires_explicit_selection() { assert!(!ProgramConfig::default().dev()); diff --git a/crates/scripts/update_revs.sh b/crates/scripts/update_revs.sh index 729d32c1f1..37a0e24c01 100755 --- a/crates/scripts/update_revs.sh +++ b/crates/scripts/update_revs.sh @@ -31,6 +31,7 @@ done echo "Press any key to continue with the update, or Ctrl+C to cancel..." read -n 1 -s echo "Updating dependencies..." -# Perform the substitution -find . -name "Cargo.toml" "${EXCLUDE_ARGS[@]}" -exec sed -i "s|rev = \"[^\"]*\"|rev = \"$CURRENT_HASH\"|g" {} \; +# Perform the substitution only on dependency lines that name this repository. Other git dependencies +# (fhe.rs, OpenVM) keep their own revisions. +find . -name "Cargo.toml" "${EXCLUDE_ARGS[@]}" -exec sed -i "\|git = \"$GITHUB_REPO_URL\"| s|rev = \"[^\"]*\"|rev = \"$CURRENT_HASH\"|g" {} \; echo "Done!" diff --git a/crates/support-scripts/src/lib.rs b/crates/support-scripts/src/lib.rs index c99172e2d0..43f410fe6a 100644 --- a/crates/support-scripts/src/lib.rs +++ b/crates/support-scripts/src/lib.rs @@ -18,10 +18,12 @@ use tokio::fs; use traits::ProgramSupportApi; pub async fn program_compile(program_config: ProgramConfig, is_dev: Option) -> Result<()> { + program_config.ensure_supported()?; ProgramSupport::new(program_config, is_dev).compile().await } pub async fn program_start(program_config: ProgramConfig, is_dev: Option) -> Result<()> { + program_config.ensure_supported()?; ProgramSupport::new(program_config, is_dev).start().await } diff --git a/crates/support/.dockerignore b/crates/support/.dockerignore index 381cbeb22e..6ac19d2e14 100644 --- a/crates/support/.dockerignore +++ b/crates/support/.dockerignore @@ -1,3 +1,2 @@ /target /contracts -Elf.sol diff --git a/examples/CRISP/.gitignore b/examples/CRISP/.gitignore index a173b28785..aa54708e44 100644 --- a/examples/CRISP/.gitignore +++ b/examples/CRISP/.gitignore @@ -5,8 +5,6 @@ out/ # Ignores development broadcast logs broadcast/ -# Autogenerated contracts -tests/Elf.sol haha/ # Dotenv file diff --git a/examples/CRISP/.interfold/support/ctl b/examples/CRISP/.interfold/support/ctl deleted file mode 120000 index e8e450169d..0000000000 --- a/examples/CRISP/.interfold/support/ctl +++ /dev/null @@ -1 +0,0 @@ -../../../../crates/support-scripts/ctl \ No newline at end of file diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index 2a05246c58..dc14686ef2 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -185,10 +185,12 @@ server: 4. Deploy CRISP with `INPUT_AVAILABILITY_SIGNER` set to the Ethereum address derived from the server's `PRIVATE_KEY`. On every network, the server `PRIVATE_KEY` must be the key of the signer address that CRISPProgram stores. - The Sepolia deployment used `USE_MOCKS=true MOCK_DATA_AVAILABILITY=false`. `USE_MOCKS=true` - deploys the mock RISC Zero verifier and the mock voting token. It also selects the mock - data-availability verifier, unless `MOCK_DATA_AVAILABILITY=false` keeps Avail. Ciphernodes read - all inputs on a chain from one data-availability source, so keep Avail on a shared network. + The current Sepolia deployment used `USE_MOCKS=true MOCK_DATA_AVAILABILITY=false` with the + earlier RISC Zero backend. `USE_MOCKS=true` deploys the mock voting token and selects the mock + data-availability verifier, unless `MOCK_DATA_AVAILABILITY=false` keeps Avail. It does not + select a compute mock: every network except the isolated local chain deploys the real OpenVM + receipt verifier. Ciphernodes read all inputs on a chain from one data-availability source, so + keep Avail on a shared network. 5. Schedule voting after the current on-chain committee setup budget. The server reads that bound from `CRISPProgram.earliestVotingStart()` and adds `VOTING_START_BUFFER_SECONDS` for transaction mining. `E3_DURATION` starts at that fixed voting time; it covers voting plus the VectorX diff --git a/examples/CRISP/crisp.dev.env.example b/examples/CRISP/crisp.dev.env.example index 708959f6fe..4b01336564 100644 --- a/examples/CRISP/crisp.dev.env.example +++ b/examples/CRISP/crisp.dev.env.example @@ -15,3 +15,9 @@ CRISP_BFV_PRESET=insecure-512 # - ciphernodes run recursive proof aggregation # When true (default): mock verifiers, no recursive aggregation build, faster DKG. CRISP_SKIP_PROOF_AGGREGATION=true + +# When 1, the local stack proves with the OpenVM worker configured under program.openvm in +# interfold.config.yaml, and the deployment installs the real receipt verifier (it needs the +# OPENVM_* deployment settings). When 0 (default), the program runs unproved against a verifier that +# accepts every receipt, which the deployment allows on the isolated local chain only. +CRISP_REAL_PROOFS=0 diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol index 5d9d836c74..d5e88e4a5e 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol @@ -289,7 +289,8 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl /// @param _initialOwner The account that can configure and bind this program. /// @param _openVmVerifier The OpenVM receipt verifier address /// @param _honkVerifier The honk verifier address - /// @param _imageId The image ID for the guest program + /// @param _imageId The receipt identity: `imageId()` of the OpenVM receipt verifier, which derives it + /// from the Halo2 verifier and the guest's executable and VM commitments constructor( address _initialOwner, IOpenVmReceiptVerifier _openVmVerifier, @@ -353,14 +354,14 @@ contract CRISPProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownabl e3Data[_e3Id].merkleRoot = _root; } - /// @notice Set the Image ID for the guest program + /// @notice Set the OpenVM receipt identity that `verify` requires. /// @dev This value is application state, not protocol state. Interfold snapshots the protocol /// ciphertext verifier for each E3 at request time, and that verifier's own `imageId` is /// immutable, so changing this value cannot replace a computation the protocol already accepted. - /// It can still break an E3 that is in flight: `verify` would then check the receipt against a - /// guest that did not produce it, the round would fail as a compute timeout, and - /// `FailurePayerLib` bills that to the requester. Change it only between rounds. - /// @param _imageId The new image ID. + /// It can still break an E3 that is in flight: `verify` would then require an identity that the + /// receipt does not have, the round would fail as a compute timeout, and `FailurePayerLib` bills + /// that to the requester. Change it only between rounds. + /// @param _imageId The new receipt identity. function setImageId(bytes32 _imageId) external onlyOwner { imageId = _imageId; } diff --git a/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmReceiptVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmReceiptVerifier.sol new file mode 100644 index 0000000000..0e8cd73ed2 --- /dev/null +++ b/examples/CRISP/packages/crisp-contracts/contracts/test/MockOpenVmReceiptVerifier.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +pragma solidity 0.8.28; + +import { IOpenVmReceiptVerifier } from "@interfold/contracts/contracts/interfaces/IOpenVmReceiptVerifier.sol"; + +/// @notice Unproved execution for isolated local integration tests only. +contract MockOpenVmReceiptVerifier is IOpenVmReceiptVerifier { + bytes32 public constant imageId = keccak256("INTERFOLD_LOCAL_UNPROVED_TEST"); + function verify(bytes calldata, bytes32, bytes32) external pure override {} +} diff --git a/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts b/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts index 3a75963551..630b208b78 100644 --- a/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts +++ b/examples/CRISP/packages/crisp-contracts/deploy/create-governance-builder.ts @@ -100,7 +100,7 @@ async function main() { if (chainId === 1) { throw new Error( - 'This partial builder cannot activate CRISP on mainnet. Run pnpm --dir packages/interfold-contracts upgrade:secure-crisp so the same DAO batch installs the secure BFV implementation and all verifier routes.', + 'This partial builder cannot activate CRISP on mainnet. Mainnet installs the OpenVM receipt verifier, the protocol ciphertext verifier route and CRISPProgram in the v0.19 cutover governance batch. Do not use upgrade:secure-crisp: it activates only the historical RISC Zero deployment.', ) } diff --git a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts index 330437576a..9b66d173e8 100644 --- a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts +++ b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts @@ -313,10 +313,26 @@ export const deployCRISPContracts = async (): Promise => return { governanceComplete } } -/** Deploy the receipt binding for an explicitly configured OpenVM Halo2 verifier. */ +/** + * Deploy the receipt binding for an explicitly configured OpenVM Halo2 verifier. + * + * `CRISP_UNPROVED_TEST=1` deploys a verifier that accepts every receipt instead. It exists for local + * development and the CRISP end-to-end test, which run the unproved development runner, and it is + * refused on every chain except the isolated local one. `USE_MOCKS` never selects it. + */ export const deployVerifier = async (_useMockVerifier: boolean, connectedEthers?: any): Promise => { const ethers = connectedEthers ?? (await hre.network.connect()).ethers const chain = getDeploymentChain(hre) + if (process.env.CRISP_UNPROVED_TEST === '1') { + if ((await ethers.provider.getNetwork()).chainId !== 31337n) { + throw new Error('CRISP_UNPROVED_TEST requires the isolated local chain (chain ID 31337)') + } + const mock = await ethers.deployContract('MockOpenVmReceiptVerifier') + await mock.waitForDeployment() + const address = await mock.getAddress() + storeDeploymentArgs({ address, blockNumber: await ethers.provider.getBlockNumber() }, 'MockOpenVmReceiptVerifier', chain) + return address + } const { receipt: verifier, halo2Verifier, halo2RuntimeCodeHash, appExeCommit, appVmCommit } = await deployOpenVmReceiptVerifier(ethers) storeDeploymentArgs( { address: halo2Verifier, blockNumber: await ethers.provider.getBlockNumber(), bytecodeHash: halo2RuntimeCodeHash }, diff --git a/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts b/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts index a73f46d13c..782226af8d 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts @@ -38,6 +38,8 @@ if (enabled) { '../../../../../packages/interfold-contracts/test/fixtures/constants' ) const { time } = networkHelpers + // `ActiveCryptoConfig.SECURE_PARAM_SET`: index 1 is historical and not accepted for new rounds. + const SECURE_PARAM_SET = 2 const abi = ethers.AbiCoder.defaultAbiCoder() const directory = path.resolve(process.env.OPENVM_E2E_OUTPUT!) if (existsSync(directory)) throw new Error('The service-test output directory must not already exist') @@ -141,7 +143,7 @@ if (enabled) { ) await (await interfold.registerE3Program(await program.getAddress())).wait() await (await program.connect(relay).bindInterfold(await interfold.getAddress())).wait() - await (await interfold.setParamSet(1, BFV_PARAMS_SECURE)).wait() + await (await interfold.setParamSet(SECURE_PARAM_SET, BFV_PARAMS_SECURE)).wait() await (await interfold.setCiphertextVerifier(ENCRYPTION_SCHEME_ID, await protocol.getAddress())).wait() const rpc = process.env.LOCAL_RPC_URL! server = spawn(path.resolve(process.env.OPENVM_E2E_SERVER!), [], { @@ -162,7 +164,7 @@ if (enabled) { CIPHERNODE_REGISTRY_ADDRESS: await registry.getAddress(), FEE_TOKEN_ADDRESS: await usdcToken.getAddress(), DATA_AVAILABILITY_MODE: 'mock', - E3_PARAM_SET: '1', + E3_PARAM_SET: String(SECURE_PARAM_SET), E3_COMMITTEE_SIZE: '0', E3_DURATION: '3600', E3_COMPUTE_PROVIDER_NAME: 'OpenVM', @@ -185,7 +187,7 @@ if (enabled) { ...system.request, e3Program: await program.getAddress(), inputWindow: [start, end], - paramSet: 1, + paramSet: SECURE_PARAM_SET, expectedCryptoConfigId: PRODUCTION_CRYPTO_CONFIG_ID, customParams: abi.encode( ['address', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256'], diff --git a/examples/CRISP/scripts/lib/dev_config.sh b/examples/CRISP/scripts/lib/dev_config.sh index 2935af0ab0..d152c4ae04 100644 --- a/examples/CRISP/scripts/lib/dev_config.sh +++ b/examples/CRISP/scripts/lib/dev_config.sh @@ -55,7 +55,18 @@ load_crisp_dev_config() { export E3_NODES__CN4__SKIP_PROOF_AGGREGATION="$CRISP_SKIP_PROOF_AGGREGATION" export E3_NODES__CN5__SKIP_PROOF_AGGREGATION="$CRISP_SKIP_PROOF_AGGREGATION" - export CRISP_BFV_PRESET CRISP_E3_PARAM_SET CRISP_SKIP_PROOF_AGGREGATION CRISP_ROOT REPO_ROOT + # Local development runs the unproved development runner against a verifier that accepts every + # receipt, on the isolated local chain only. CRISP_REAL_PROOFS=1 uses the OpenVM worker configured + # under program.openvm and deploys the real receipt verifier instead. + CRISP_REAL_PROOFS="${CRISP_REAL_PROOFS:-0}" + if [[ "$CRISP_REAL_PROOFS" == "1" ]]; then + unset CRISP_UNPROVED_TEST E3_PROGRAM__DEV + else + export CRISP_UNPROVED_TEST=1 + export E3_PROGRAM__DEV=true + fi + + export CRISP_BFV_PRESET CRISP_E3_PARAM_SET CRISP_SKIP_PROOF_AGGREGATION CRISP_ROOT REPO_ROOT CRISP_REAL_PROOFS } apply_crisp_dev_config_to_server_env() { diff --git a/packages/interfold-contracts/contracts/lib/Risc0ComputeProof.sol b/packages/interfold-contracts/contracts/lib/Risc0ComputeProof.sol index 33f1bd38b8..50bd43ae5d 100644 --- a/packages/interfold-contracts/contracts/lib/Risc0ComputeProof.sol +++ b/packages/interfold-contracts/contracts/lib/Risc0ComputeProof.sol @@ -7,7 +7,8 @@ pragma solidity 0.8.28; /** * @title Risc0ComputeProof - * @notice Decodes the compute proof and rebuilds the journal emitted by the current guest. + * @notice Decodes the compute proof and rebuilds the journal of the legacy RISC Zero guest. Kept for + * the RISC Zero deployments and the rounds that snapshot them; new programs use OpenVmComputeProof. */ library Risc0ComputeProof { uint256 internal constant FIELD_SIZE = 132; diff --git a/packages/interfold-contracts/scripts/genManifest.ts b/packages/interfold-contracts/scripts/genManifest.ts index 4553c5c39e..658bacf0c5 100644 --- a/packages/interfold-contracts/scripts/genManifest.ts +++ b/packages/interfold-contracts/scripts/genManifest.ts @@ -87,6 +87,9 @@ const REFERENCE_KEYS = [ "BfvDecryptionVerifierRouter", "BfvPkVerifierRouter", "Risc0BfvCiphertextVerifier", + "OpenVmBfvCiphertextVerifier", + "OpenVmReceiptVerifier", + "OpenVmHalo2Verifier", ]; /** diff --git a/scripts/README.md b/scripts/README.md index 7e8f340d10..308252183c 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -532,8 +532,8 @@ The provenance command records the OpenVM compute guest. The full reviewer-facin ### `generate-provenance-manifest.ts` -Records the source commit, lockfile digests, guest configuration, optimization patch, proving -artifacts, KZG parameters, and application commitments. With `--prover`, it checks the worker's +Records the source commit, lockfile digests, guest configuration, proving artifacts, KZG +parameters, and application commitments. With `--prover`, it checks the worker's configured identity. With an RPC, it checks the protocol-to-receipt binding, application commitments, and deployed Halo2 runtime against the checked artifact. These RPC checks do not send transactions. diff --git a/scripts/check-addresses.ts b/scripts/check-addresses.ts index ec139a9137..4bf8c3e35a 100644 --- a/scripts/check-addresses.ts +++ b/scripts/check-addresses.ts @@ -178,6 +178,9 @@ const LABELS: Record = { BfvDecryptionVerifierRouter: 'BfvDecryptionVerifierRouter', BfvPkVerifierRouter: 'BfvPkVerifierRouter', Risc0BfvCiphertextVerifier: 'Risc0BfvCiphertextVerifier', + OpenVmBfvCiphertextVerifier: 'OpenVmBfvCiphertextVerifier', + OpenVmReceiptVerifier: 'OpenVmReceiptVerifier', + OpenVmHalo2Verifier: 'OpenVmHalo2Verifier', } /** Files this check never reads, whatever they contain. */ diff --git a/templates/default/.interfold/support/ctl b/templates/default/.interfold/support/ctl deleted file mode 120000 index e8e450169d..0000000000 --- a/templates/default/.interfold/support/ctl +++ /dev/null @@ -1 +0,0 @@ -../../../../crates/support-scripts/ctl \ No newline at end of file diff --git a/templates/default/contracts/MyProgram.sol b/templates/default/contracts/MyProgram.sol index e530741047..befb0f0a96 100755 --- a/templates/default/contracts/MyProgram.sol +++ b/templates/default/contracts/MyProgram.sol @@ -48,7 +48,8 @@ contract MyProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownable { /// @notice Bind the program to its OpenVM receipt verifier. /// @param _interfold The Interfold contract address /// @param _verifier The OpenVM receipt verifier address - /// @param _imageId The image ID for the guest program + /// @param _imageId The receipt identity: `imageId()` of the OpenVM receipt verifier, which derives it + /// from the Halo2 verifier and the guest's executable and VM commitments constructor(IInterfold _interfold, IOpenVmReceiptVerifier _verifier, bytes32 _imageId) Ownable(msg.sender) { require(address(_verifier) != address(0), VerifierAddressZero()); From 3c47dea4cd729a5acc84609b16a87a7dc3c381fd Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 17:14:35 +0500 Subject: [PATCH 05/20] feat!: prove each project's own program with streamed OpenVM inputs The OpenVM path proved only CRISP's policy and capped a round at 1,024 inputs. - e3-compute-provider: `SecureProcess` reads a round in two passes, one ciphertext at a time: every input for its leaf, commitment and Keccak hash, then the selected inputs again, each refused unless it matches its first-pass hash. `ComputeInput::run` runs the same code over a round held in memory. The processor takes the selected ciphertexts as an iterator, and selection sees an `InputRecord` without ciphertext bytes. - Each project has its own guest (`guest/`) and proving service (`.interfold/support/openvm`), both linked to the project's `program/`. The guest's 512 MiB no longer bounds a round. - e3-openvm-host runs the program natively, writes the guest's input stream and runs the worker. At startup it uses the CUDA worker when one is configured and its `probe` opens a GPU, and otherwise the CPU worker. Every worker run has a deadline and is stopped at it. - interfold-openvm-prover (moved to crates/openvm-prover) reads framed input items, loads the Halo2 key and KZG parameters in `check`, and gains `probe` and `write-config`. - e3-program-server admits a request before reading its body, takes a configurable body limit, and retries callbacks. - `program.openvm` takes `prover_bin`, `prover_bin_cuda`, `backend`, `prover_config` and `setup_dir`. `interfold program compile` builds the guest, keys, receipt identity, worker configuration and service; the template and CRISP deploys read that identity by default. - `interfold init` copies the OpenVM service folder and pins the guest's Interfold crates to the template commit. --- .dockerignore | 6 + Cargo.lock | 20 + Cargo.toml | 9 +- agent/CRATES_ARCHITECTURE.md | 23 +- agent/flow-trace/04_DKG_AND_COMPUTATION.md | 11 +- agent/flow-trace/08_DATA_AVAILABILITY.md | 2 +- crates/compute-provider/Readme.md | 51 +- crates/compute-provider/src/compute_input.rs | 274 +- crates/compute-provider/src/lib.rs | 4 +- .../src/merkle_tree_builder.rs | 149 +- crates/compute-provider/src/policy.rs | 54 +- crates/compute-provider/src/secure_process.rs | 583 ++++ crates/config/src/app_config.rs | 7 +- crates/config/src/program_config.rs | 64 +- crates/init/src/lib.rs | 18 + crates/openvm-host/Cargo.toml | 14 + crates/openvm-host/src/lib.rs | 490 +++ .../prover => openvm-prover}/Cargo.lock | 0 .../prover => openvm-prover}/Cargo.toml | 4 +- crates/openvm-prover/README.md | 198 ++ .../prover => openvm-prover}/src/main.rs | 209 +- crates/openvm-types/Cargo.toml | 12 + crates/openvm-types/src/lib.rs | 309 ++ crates/program-server/src/lib.rs | 100 +- crates/support-scripts/openvm/compile | 71 + .../support-scripts/openvm/service/Cargo.toml | 15 + .../openvm/service/src/main.rs | 67 + crates/support-scripts/openvm/start | 9 + crates/support-scripts/src/program_openvm.rs | 64 +- crates/support/Cargo.toml | 50 - crates/support/Dockerfile | 13 +- crates/support/README.md | 102 - crates/support/app/Cargo.toml | 19 - crates/support/app/src/main.rs | 436 --- crates/support/host/Cargo.toml | 23 - crates/support/host/README.md | 11 - crates/support/host/src/lib.rs | 157 - crates/support/openvm/README.md | 166 - crates/support/openvm/guest/src/main.rs | 35 - crates/support/program/Cargo.toml | 21 - crates/support/program/src/lib.rs | 163 - crates/support/scripts/container/build.sh | 3 - crates/support/scripts/container/start.sh | 5 - crates/support/types/Cargo.toml | 13 - crates/support/types/src/lib.rs | 382 --- examples/CRISP/.interfold/support/openvm | 1 + examples/CRISP/Cargo.lock | 40 +- examples/CRISP/Cargo.toml | 2 + examples/CRISP/Readme.md | 40 +- .../CRISP}/guest/Cargo.lock | 52 +- .../CRISP}/guest/Cargo.toml | 15 +- .../CRISP}/guest/openvm.toml | 0 examples/CRISP/guest/src/main.rs | 50 + examples/CRISP/interfold.config.yaml | 8 +- .../packages/crisp-contracts/deploy/crisp.ts | 11 +- examples/CRISP/program/README.md | 6 +- examples/CRISP/program/src/lib.rs | 35 +- examples/CRISP/program/tests/input_leaf.rs | 3 + .../program/tests/onchain_root_agreement.rs | 22 +- .../CRISP/program/tests/secure_process.rs | 95 +- examples/CRISP/program/tests/selection.rs | 14 +- examples/CRISP/server/src/server/repo.rs | 8 +- .../interfold-contracts/scripts/openVm.ts | 44 +- scripts/generate-provenance-manifest.ts | 8 +- scripts/run-openvm.sh | 39 +- templates/default/.gitignore | 1 + templates/default/.gitignore.bak | 1 + templates/default/.interfold/support/openvm | 1 + templates/default/Cargo.lock | 106 +- templates/default/Cargo.toml | 4 +- templates/default/README.md | 23 +- templates/default/deploy/default.ts | 6 +- .../default/guest}/Cargo.lock | 2682 +++++------------ templates/default/guest/Cargo.toml | 24 + templates/default/guest/openvm.toml | 7 + templates/default/guest/src/main.rs | 50 + templates/default/interfold.config.yaml | 10 +- templates/default/program/Cargo.toml | 5 + templates/default/program/src/lib.rs | 15 +- 79 files changed, 3817 insertions(+), 4047 deletions(-) create mode 100644 crates/compute-provider/src/secure_process.rs create mode 100644 crates/openvm-host/Cargo.toml create mode 100644 crates/openvm-host/src/lib.rs rename crates/{support/openvm/prover => openvm-prover}/Cargo.lock (100%) rename crates/{support/openvm/prover => openvm-prover}/Cargo.toml (69%) create mode 100644 crates/openvm-prover/README.md rename crates/{support/openvm/prover => openvm-prover}/src/main.rs (53%) create mode 100644 crates/openvm-types/Cargo.toml create mode 100644 crates/openvm-types/src/lib.rs create mode 100755 crates/support-scripts/openvm/compile create mode 100644 crates/support-scripts/openvm/service/Cargo.toml create mode 100644 crates/support-scripts/openvm/service/src/main.rs create mode 100755 crates/support-scripts/openvm/start delete mode 100644 crates/support/Cargo.toml delete mode 100644 crates/support/README.md delete mode 100644 crates/support/app/Cargo.toml delete mode 100644 crates/support/app/src/main.rs delete mode 100644 crates/support/host/Cargo.toml delete mode 100644 crates/support/host/README.md delete mode 100644 crates/support/host/src/lib.rs delete mode 100644 crates/support/openvm/README.md delete mode 100644 crates/support/openvm/guest/src/main.rs delete mode 100644 crates/support/program/Cargo.toml delete mode 100644 crates/support/program/src/lib.rs delete mode 100755 crates/support/scripts/container/build.sh delete mode 100755 crates/support/scripts/container/start.sh delete mode 100644 crates/support/types/Cargo.toml delete mode 100644 crates/support/types/src/lib.rs create mode 120000 examples/CRISP/.interfold/support/openvm rename {crates/support/openvm => examples/CRISP}/guest/Cargo.lock (99%) rename {crates/support/openvm => examples/CRISP}/guest/Cargo.toml (50%) rename {crates/support/openvm => examples/CRISP}/guest/openvm.toml (100%) create mode 100644 examples/CRISP/guest/src/main.rs create mode 120000 templates/default/.interfold/support/openvm rename {crates/support => templates/default/guest}/Cargo.lock (61%) create mode 100644 templates/default/guest/Cargo.toml create mode 100644 templates/default/guest/openvm.toml create mode 100644 templates/default/guest/src/main.rs diff --git a/.dockerignore b/.dockerignore index 2e8880000a..29e57b338d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,6 +7,12 @@ !Cargo.lock !crates/**/* !examples/CRISP/program/**/* +# CRISP's OpenVM proving service (crates/support/Dockerfile) builds in the CRISP workspace. +!examples/CRISP/Cargo.toml +!examples/CRISP/Cargo.lock +!examples/CRISP/.interfold/support/** +!examples/CRISP/server/**/* +!examples/CRISP/crates/**/* !packages/**/* !package.json !pnpm-workspace.yaml diff --git a/Cargo.lock b/Cargo.lock index ac8ee8c256..b0d1243e28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4329,6 +4329,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "e3-openvm-host" +version = "0.19.0-test.2" +dependencies = [ + "anyhow", + "e3-compute-provider", + "e3-openvm-types", + "tempfile", + "tokio", +] + +[[package]] +name = "e3-openvm-types" +version = "0.19.0-test.2" +dependencies = [ + "bincode", + "e3-compute-provider", + "serde", +] + [[package]] name = "e3-parity-matrix" version = "0.19.0-test.2" diff --git a/Cargo.toml b/Cargo.toml index fa3a313669..6e36eee74e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,8 @@ members = [ "crates/logger", "crates/multithread", "crates/net", + "crates/openvm-host", + "crates/openvm-types", "crates/parity-matrix", "crates/polynomial", "crates/program-server", @@ -52,9 +54,10 @@ exclude = [ "examples/CRISP", "examples/CRISP/server", "examples/CRISP/program", - # client needs to be able to build crates/support independently - "crates/support", + # Built with the OpenVM SDK as a workspace of its own. + "crates/openvm-prover", "crates/support-scripts/dev", + "crates/support-scripts/openvm", "templates/default" ] resolver = "3" @@ -107,6 +110,8 @@ e3-keyshare = { version = "0.19.0-test.2", path = "./crates/keyshare" } e3-logger = { version = "0.19.0-test.2", path = "./crates/logger" } e3-net = { version = "0.19.0-test.2", path = "./crates/net" } e3-compute-provider = { version = "0.19.0-test.2", path = "./crates/compute-provider" } +e3-openvm-host = { version = "0.19.0-test.2", path = "./crates/openvm-host" } +e3-openvm-types = { version = "0.19.0-test.2", path = "./crates/openvm-types" } e3-sortition = { version = "0.19.0-test.2", path = "./crates/sortition" } e3-daemon-server = { version = "0.19.0-test.2", path = "./crates/daemon-server" } e3-program-server = { version = "0.19.0-test.2", path = "./crates/program-server" } diff --git a/agent/CRATES_ARCHITECTURE.md b/agent/CRATES_ARCHITECTURE.md index 2c3603714a..943e17b3a8 100644 --- a/agent/CRATES_ARCHITECTURE.md +++ b/agent/CRATES_ARCHITECTURE.md @@ -1400,16 +1400,21 @@ are not introduced solely to create layers. ### OpenVM compute support -The isolated `crates/support` workspace serves CRISP compute requests. Its native host calls the -separate `crates/support/openvm/prover` worker and accepts only a verified OpenVM EVM receipt. -The guest and host share the canonical CRISP policy source. The normal `e3-support-scripts` -backend uses `program.openvm`; it no longer selects RISC Zero or Boundless. -The worker validates the executable, VM identity, aggregation key, verifier artifact, and journal. +Each project proves its own E3 program. Its `guest/` crate (its own workspace, built with +`cargo openvm`) and the `.interfold/support/openvm` service both link the project's `program/`, so +the guest, the native host, and the contract share one policy source. The service is an +`e3-program-server` whose runner is `e3-openvm-host`: it runs the shared `SecureProcess` natively, +writes the guest's input stream (a header, every ciphertext, then the selected ones), and runs the +separate `interfold-openvm-prover` worker (`crates/openvm-prover`, its own workspace). It accepts +only a verified OpenVM EVM receipt. The guest reads one ciphertext at a time, so a round is not +bounded by guest memory. The worker validates the executable, VM identity, aggregation key, Halo2 +key and parameters, verifier artifact, and journal. At startup the host picks the CUDA worker when +it is configured and can open a GPU, and otherwise the CPU worker; every worker run has a deadline. Jobs remain in memory; this service does not provide durable admission or restart recovery. -`interfold program compile` builds the native service. Guest compilation and key preparation are -separate steps. The CLI has no program-upload or container-shell command. `e3-init` does not install -an external verifier submodule or copy the old container controls. `program.dev` is an explicit, -unproved runner; normal startup requires the OpenVM configuration. +`interfold program compile` builds the guest, keys, receipt identity, worker configuration, and +service; `e3-init` copies the service folder and pins the guest's Interfold crates to the template +commit. The normal `e3-support-scripts` backend uses `program.openvm`; it no longer selects RISC +Zero or Boundless. `program.dev` is an explicit, unproved runner. CRISP's encrypted-input and result-callback routes accept at most 4 MiB of JSON, to contain the largest supported DA object after hexadecimal encoding. This limit is scoped to those routes; diff --git a/agent/flow-trace/04_DKG_AND_COMPUTATION.md b/agent/flow-trace/04_DKG_AND_COMPUTATION.md index b0b293baeb..3e9c58c523 100644 --- a/agent/flow-trace/04_DKG_AND_COMPUTATION.md +++ b/agent/flow-trace/04_DKG_AND_COMPUTATION.md @@ -1124,16 +1124,19 @@ deadlines, recovery flow, and remaining trust. ### Ciphertext Output Publication -The support host sends raw bincode input to the OpenVM guest. The native host and guest use the -same CRISP policy source. The guest commits nine 32-byte ABI words in this order: chain ID, +The OpenVM host streams the round to the guest one item at a time: a bincode header (domain, +parameters, on-chain indices, published commitments and metadata), every ciphertext in index order, +then the selected ciphertexts again. The guest keeps a hash of each ciphertext from the first pass +and refuses a second-pass ciphertext that differs. The native host and guest run the same +`SecureProcess` with the project's policy. The guest commits nine 32-byte ABI words in this order: chain ID, Interfold address, full uint256 E3 ID, encryption scheme ID, committee public-key hash, output hash, SAFE commitment, parameter hash, and input root. It reveals SHA-256 of these 288 bytes. -The support worker generates an application proof, recursive aggregate, and Halo2 EVM proof. +The OpenVM worker generates an application proof, recursive aggregate, and Halo2 EVM proof. It checks the configured executable and VM commitments and verifies the EVM proof against the native journal before it returns a seal. The app returns the seal, parameter hash, and input root in one ABI-encoded proof. Missing configuration or a failed proof cannot select a fake-proof mode. -See `crates/support/openvm/README.md` for the build and deployment boundary. Existing RISC Zero +See `crates/openvm-prover/README.md` for the build and deployment boundary. Existing RISC Zero deployment records are not migrated by this source change. The request-time scheme verifier reconstructs the protocol fields from on-chain state. The E3 diff --git a/agent/flow-trace/08_DATA_AVAILABILITY.md b/agent/flow-trace/08_DATA_AVAILABILITY.md index ceebbe37c0..02d4b6258d 100644 --- a/agent/flow-trace/08_DATA_AVAILABILITY.md +++ b/agent/flow-trace/08_DATA_AVAILABILITY.md @@ -544,7 +544,7 @@ provider, or on a later adapter, keeps working. The normal unit and contract suites do not reproduce the deployed OpenVM guest. Before deployment, build the guest and worker from the pinned source and validate their application commitments with the worker's `check` command. Deploy a checked Halo2 artifact and bind both verification gates to -the same receipt identity. Follow `crates/support/openvm/README.md` and the provenance procedure. +the same receipt identity. Follow `crates/openvm-prover/README.md` and the provenance procedure. A native computation does not replace this proof check. After the guest is rebuilt, run the full local CRISP Playwright flow and one Sepolia round with real diff --git a/crates/compute-provider/Readme.md b/crates/compute-provider/Readme.md index 215722a163..25a5b37973 100644 --- a/crates/compute-provider/Readme.md +++ b/crates/compute-provider/Readme.md @@ -42,7 +42,25 @@ where ``` `fhe_processor` is your own function. It must match the exported `FHEProcessor` alias, -`fn(&FHEInputs) -> Vec`. +`fn(FHEProcessorInput) -> Vec`. The selected ciphertexts arrive one at a time through an +iterator, each with its on-chain index, so a zkVM guest never holds the whole round: + +```rust +use e3_compute_provider::FHEProcessorInput; +use fhe::bfv::Ciphertext; +use fhe_traits::{DeserializeParametrized, Serialize}; + +pub fn fhe_processor(input: FHEProcessorInput<'_>) -> Vec { + let mut sum = Ciphertext::zero(input.params); + for (bytes, _index) in input.ciphertexts { + sum += &Ciphertext::from_bytes(&bytes, input.params).unwrap(); + } + sum.to_bytes() +} +``` + +The processor must read every item. Keep per-input state small: the OpenVM guest has 512 MiB of +memory for the whole computation. ## Input policies @@ -55,7 +73,7 @@ Both are plain function pointers, so a policy is a value rather than a trait imp ```rust pub type LeafFn = fn(&PublishedInput) -> Result; -pub type SelectFn = fn(&[PublishedInput]) -> Vec; +pub type SelectFn = fn(&[InputRecord]) -> Vec; ``` A leaf is returned as hex, already reduced into the BN254 scalar field. `leaf_from_digest` does that @@ -67,7 +85,7 @@ use e3_compute_provider::ComputeError; use sha2::{Digest, Sha256}; fn my_leaf(input: &PublishedInput) -> Result { - let digest = Sha256::digest([input.ciphertext, input.metadata].concat()); + let digest = Sha256::digest([&input.ciphertext_hash[..], input.metadata].concat()); Ok(leaf_from_digest(&digest)) } @@ -79,9 +97,15 @@ pub fn policy() -> InputPolicy { } ``` -`PublishedInput` carries the input's `index`, its `ciphertext` bytes, the `commitment` the program -stored when it stores one, whatever `metadata` it published, and `recomputed`, the commitment -derived from the bytes. `matches_commitment()` compares `commitment` against `recomputed`. +`PublishedInput` carries the input's `index`, its `ciphertext` bytes and their Keccak-256 +`ciphertext_hash`, the `commitment` the program stored when it stores one, whatever `metadata` it +published, and `recomputed`, the commitment derived from the bytes. `matches_commitment()` compares +`commitment` against `recomputed`. + +`select` receives an `InputRecord` per input: the same fields without the ciphertext bytes. The +Secure Process reads each ciphertext once to build its leaf and does not keep it, so selection works +on what remains. The selected ciphertexts are read again, and each is refused unless it hashes to the +`ciphertext_hash` of its first read. `InputPolicy::default()` is the behaviour every E3 program had before policies existed. The leaf is the ciphertext's own SAFE commitment, and every input is computed over. A program whose contract @@ -125,10 +149,17 @@ impl ComputeProvider for MyProvider { `prove` receives the policy rather than choosing one. A prover that picked its own would select a different input set from the one `start` returned the ciphertext for. -The OpenVM host lives in `e3-support-host`, in a separate workspace. Its `run_compute` function -derives the native ciphertext and journal, then calls a separate OpenVM worker. The worker must -return a verified EVM receipt. Read `crates/support/host/src/lib.rs` and -`crates/support/openvm/README.md` for the implementation and configuration. +## The Secure Process + +`SecureProcess` is the computation every provider must reproduce. It reads a round in two passes: +every ciphertext in index order (`absorb`), then the selected ones again (`select`, then `finish`). +Only one ciphertext is held at a time, which is how the OpenVM guest proves rounds larger than its +memory. `ComputeInput::run` runs the same code over a round held in memory, and +`ComputeInput::run_selected` also returns the indices of the second pass. + +The OpenVM provider is `e3-openvm-host`. It runs the program natively, writes the guest's input +stream, and calls the separate `interfold-openvm-prover` worker, which returns a verified EVM +receipt. See `crates/openvm-prover/README.md`. ## Configuration diff --git a/crates/compute-provider/src/compute_input.rs b/crates/compute-provider/src/compute_input.rs index 6154547782..5560b51cee 100644 --- a/crates/compute-provider/src/compute_input.rs +++ b/crates/compute-provider/src/compute_input.rs @@ -5,17 +5,13 @@ // or FITNESS FOR A PARTICULAR PURPOSE. use crate::ciphertext_output::ComputeResult; -use crate::hashing::keccak256; -use crate::merkle_tree_builder::{Batching, MerkleTreeBuilder}; +use crate::merkle_tree_builder::Batching; use crate::policy::InputPolicy; -#[cfg(test)] -use e3_bfv_client::client::compute_ct_commitment; -use e3_bfv_client::client::compute_ct_commitment_with_params; -use e3_fhe_params::decode_bfv_params_arc; +use crate::secure_process::{absorb_all, SecureProcess}; use fhe::bfv::BfvParameters; use std::sync::Arc; -pub type FHEProcessor = for<'a> fn(&FHEProcessorInput<'a>) -> Vec; +pub type FHEProcessor = for<'a> fn(FHEProcessorInput<'a>) -> Vec; /// Inputs passed to an E3 program's homomorphic processor. /// @@ -23,7 +19,12 @@ pub type FHEProcessor = for<'a> fn(&FHEProcessorInput<'a>) -> Vec; /// secure parameter tables is expensive inside a zkVM, and decoding the same immutable bytes twice /// adds no verification. pub struct FHEProcessorInput<'a> { - pub ciphertexts: &'a [(Vec, u64)], + /// The selected ciphertexts in index order, each paired with its on-chain index. + /// + /// Read one at a time: inside the zkVM each is read from the input stream and checked only when + /// the processor asks for it, so a round never has to fit in memory at once. The processor must + /// read every item. + pub ciphertexts: &'a mut dyn Iterator, u64)>, pub params: &'a Arc, } @@ -85,6 +86,15 @@ pub enum ComputeError { #[error("failed to build the input Merkle tree: {0}")] MerkleTree(String), + + #[error("the round has {expected} inputs, but {actual} were read")] + InputCount { expected: usize, actual: usize }, + + #[error("input {index} differs from the ciphertext read in the first pass")] + InputChanged { index: usize }, + + #[error("the processor returned before reading {remaining} selected inputs")] + Unread { remaining: usize }, } impl ComputeInput { @@ -126,100 +136,61 @@ impl ComputeInput { policy: InputPolicy, batching: Batching, ) -> Result<(ComputeResult, Vec), ComputeError> { - self.run_observed(fhe_processor, policy, batching, |_, _| {}) + self.run_selected(fhe_processor, policy, batching) + .map(|(result, ciphertext, _)| (result, ciphertext)) } - /// As [`Self::run_batched`], and reports phase boundaries without exposing or changing the - /// computed values. The observer receives `true` at the start and `false` at the end of each - /// phase. A failed phase does not emit an end event. - pub fn run_observed( + /// As [`Self::run_batched`], and also returns the indices the policy selected. + /// + /// Runs the same [`SecureProcess`] a zkVM guest runs over a streamed round, so the result is + /// the journal the guest proves. The selection names the ciphertexts the guest reads in its + /// second pass. + pub fn run_selected( &self, fhe_processor: FHEProcessor, policy: InputPolicy, batching: Batching, - mut observe: impl FnMut(&'static str, bool), - ) -> Result<(ComputeResult, Vec), ComputeError> { - observe("params", true); - let params = decode_bfv_params_arc(&self.fhe_inputs.params) - .map_err(|e| ComputeError::DecodeParams(e.to_string()))?; - observe("params", false); - - if !self.published.is_empty() && self.published.len() != self.fhe_inputs.ciphertexts.len() { - return Err(ComputeError::MerkleTree(format!( - "{} ciphertexts but {} published entries", - self.fhe_inputs.ciphertexts.len(), - self.published.len() - ))); - } - - observe("input_commitments_and_selection", true); - let mut tree_builder = MerkleTreeBuilder::new(self.fhe_inputs.ciphertexts.len()); - let selected = tree_builder.compute_leaf_hashes_batched( - &self.fhe_inputs, - &self.published, - ¶ms, + ) -> Result<(ComputeResult, Vec, Vec), ComputeError> { + let ciphertexts = &self.fhe_inputs.ciphertexts; + let mut process = SecureProcess::new( + &self.fhe_inputs.params, + ciphertexts.iter().map(|(_, index)| *index).collect(), + self.published.clone(), policy, - batching, )?; - observe("input_commitments_and_selection", false); - observe("input_tree", true); - let merkle_root = tree_builder - .build_tree() - .map_err(|e| ComputeError::MerkleTree(e.to_string()))? - .root() - .ok_or_else(|| ComputeError::MerkleTree("the tree has no root".into()))?; - observe("input_tree", false); + absorb_all(&mut process, ciphertexts, batching)?; - // The processor sees only what the policy selected. Both the root above and this set are + let selected = process.select()?; + let indices = selected.indices().to_vec(); + // The processor sees only what the policy selected. Both the root and this set are // functions of values the root binds, so any prover over the same published inputs reaches // the same result. - observe("fhe_processor", true); - let processed_ciphertext = (fhe_processor)(&FHEProcessorInput { - ciphertexts: &selected, - params: ¶ms, - }); - observe("fhe_processor", false); - observe("output_hash", true); - let processed_hash = keccak256(&processed_ciphertext).to_vec(); - observe("output_hash", false); - observe("output_commitment", true); - let ciphertext_commitment = - compute_ct_commitment_with_params(&processed_ciphertext, ¶ms) - .map_err(|e| ComputeError::OutputCommitment(e.to_string()))? - .to_vec(); - observe("output_commitment", false); - observe("params_hash", true); - let params_hash = keccak256(&self.fhe_inputs.params).to_vec(); - observe("params_hash", false); - - Ok(( - ComputeResult { - ciphertext_hash: processed_hash, - ciphertext_commitment, - params_hash, - merkle_root: hex::decode(merkle_root) - .map_err(|e| ComputeError::MerkleTree(e.to_string()))?, - }, - processed_ciphertext, - )) + let (result, ciphertext) = + selected.finish(fhe_processor, |index| Ok(ciphertexts[index].0.clone()))?; + Ok((result, ciphertext, indices)) } } #[cfg(test)] mod tests { use super::*; - use crate::policy::{all_inputs, commitment_leaf, PublishedInput}; - use e3_fhe_params::{build_pair_for_preset, encode_bfv_params, BfvPreset}; + use crate::merkle_tree_builder::MerkleTreeBuilder; + use crate::policy::{all_inputs, commitment_leaf, InputRecord, PublishedInput}; + use e3_bfv_client::client::compute_ct_commitment; + use e3_fhe_params::{ + build_pair_for_preset, decode_bfv_params_arc, encode_bfv_params, BfvPreset, + }; use fhe::bfv::{Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; use fhe_traits::{FheEncoder, FheEncrypter, Serialize as FheSerialize}; use rand::SeedableRng; use rand_chacha::ChaCha8Rng; use sha3::{Digest, Keccak256}; - fn sum_processor(inputs: &FHEProcessorInput<'_>) -> Vec { + + fn sum_processor(inputs: FHEProcessorInput<'_>) -> Vec { + use fhe_traits::DeserializeParametrized; let mut sum = Ciphertext::zero(inputs.params); for (bytes, _) in inputs.ciphertexts { - use fhe_traits::DeserializeParametrized; - sum += &Ciphertext::from_bytes(bytes, inputs.params).unwrap(); + sum += &Ciphertext::from_bytes(&bytes, inputs.params).unwrap(); } sum.to_bytes() } @@ -247,12 +218,43 @@ mod tests { } } - fn process(inputs: FHEInputs, policy: InputPolicy) -> Result { + fn input(inputs: FHEInputs) -> ComputeInput { ComputeInput { fhe_inputs: inputs, published: Vec::new(), } - .process(sum_processor, policy) + } + + fn process(inputs: FHEInputs, policy: InputPolicy) -> Result { + input(inputs).process(sum_processor, policy) + } + + /// The root of a tree whose leaves are each input's own commitment, built independently of the + /// Secure Process. + fn commitment_root(inputs: &FHEInputs) -> Vec { + let params = decode_bfv_params_arc(&inputs.params).unwrap(); + let leaves = inputs + .ciphertexts + .iter() + .map(|(bytes, _)| { + hex::encode( + compute_ct_commitment( + bytes.clone(), + params.degree(), + params.plaintext(), + params.moduli().to_vec(), + ) + .unwrap(), + ) + }) + .collect(); + let root = MerkleTreeBuilder::new(inputs.ciphertexts.len()) + .with_leaf_hashes(leaves) + .build_tree() + .unwrap() + .root() + .unwrap(); + hex::decode(root).unwrap() } /// The journal's input root must be a function of the ciphertexts consumed. Before this, the @@ -261,17 +263,10 @@ mod tests { #[test] fn the_root_is_derived_from_the_processed_ciphertexts() { let inputs = encrypted_inputs(&[1, 1, 1]); - let params = decode_bfv_params_arc(&inputs.params).unwrap(); let result = process(inputs.clone(), InputPolicy::default()).unwrap(); - let mut builder = MerkleTreeBuilder::new(3); - builder - .compute_leaf_hashes(&inputs, &[], ¶ms, InputPolicy::default()) - .unwrap(); - let expected = hex::decode(builder.build_tree().unwrap().root().unwrap()).unwrap(); - - assert_eq!(result.merkle_root, expected); + assert_eq!(result.merkle_root, commitment_root(&inputs)); } /// Changing the consumed ciphertexts must change the published root, so an E3 program's @@ -292,22 +287,13 @@ mod tests { #[test] fn the_default_policy_uses_the_ciphertext_commitment_and_keeps_every_input() { let inputs = encrypted_inputs(&[4, 5]); - let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let mut builder = MerkleTreeBuilder::new(2); - let selected = builder - .compute_leaf_hashes(&inputs, &[], ¶ms, InputPolicy::default()) + let (result, _, selected) = input(inputs.clone()) + .run_selected(sum_processor, InputPolicy::default(), Batching::Sequential) .unwrap(); - assert_eq!(selected.len(), 2, "every input is computed over"); - let commitment = compute_ct_commitment( - inputs.ciphertexts[0].0.clone(), - params.degree(), - params.plaintext(), - params.moduli().to_vec(), - ) - .unwrap(); - assert_eq!(builder.leaf_hashes[0], hex::encode(commitment)); + assert_eq!(selected, vec![0, 1], "every input is computed over"); + assert_eq!(result.merkle_root, commitment_root(&inputs)); } /// A policy chooses what is computed over; it cannot shrink the tree. Dropping a leaf would @@ -315,29 +301,26 @@ mod tests { /// trusting each program to. #[test] fn a_policy_cannot_drop_an_input_from_the_tree() { - fn select_nothing(_: &[PublishedInput]) -> Vec { - Vec::new() + fn select_the_first(_: &[InputRecord]) -> Vec { + vec![0] } let inputs = encrypted_inputs(&[1, 2, 3]); - let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let mut builder = MerkleTreeBuilder::new(3); - let selected = builder - .compute_leaf_hashes( - &inputs, - &[], - ¶ms, + let (result, _, selected) = input(inputs.clone()) + .run_selected( + sum_processor, InputPolicy { leaf: commitment_leaf, - select: select_nothing, + select: select_the_first, }, + Batching::Sequential, ) .unwrap(); - assert!(selected.is_empty(), "the policy selected nothing"); + assert_eq!(selected, vec![0], "the policy selected one input"); assert_eq!( - builder.leaf_hashes.len(), - 3, + result.merkle_root, + commitment_root(&inputs), "every leaf is still in the tree" ); } @@ -345,23 +328,18 @@ mod tests { /// A policy returning an index that does not exist is a bug in the program, not a silent skip. #[test] fn an_out_of_range_selection_is_rejected() { - fn select_beyond_the_end(_: &[PublishedInput]) -> Vec { + fn select_beyond_the_end(_: &[InputRecord]) -> Vec { vec![99] } - let inputs = encrypted_inputs(&[1]); - let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let error = MerkleTreeBuilder::new(1) - .compute_leaf_hashes( - &inputs, - &[], - ¶ms, - InputPolicy { - leaf: commitment_leaf, - select: select_beyond_the_end, - }, - ) - .unwrap_err(); + let error = process( + encrypted_inputs(&[1]), + InputPolicy { + leaf: commitment_leaf, + select: select_beyond_the_end, + }, + ) + .unwrap_err(); assert!( matches!(error, ComputeError::MerkleTree(_)), @@ -391,11 +369,8 @@ mod tests { fn the_default_policy_reports_the_index_of_an_undecodable_input() { let mut inputs = encrypted_inputs(&[1, 1]); inputs.ciphertexts[1].0 = vec![0xff; 8]; - let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let error = MerkleTreeBuilder::new(2) - .compute_leaf_hashes(&inputs, &[], ¶ms, InputPolicy::default()) - .unwrap_err(); + let error = process(inputs, InputPolicy::default()).unwrap_err(); assert!( matches!(error, ComputeError::LeafCommitment { index: 1, .. }), @@ -414,10 +389,7 @@ mod tests { fn batching_does_not_change_the_root() { let inputs = encrypted_inputs(&[3, 1, 4, 1, 5, 9, 2, 6]); let policy = InputPolicy::default(); - let input = ComputeInput { - fhe_inputs: inputs, - published: Vec::new(), - }; + let input = input(inputs); let (sequential, sequential_ciphertext) = input.run(sum_processor, policy).unwrap(); @@ -449,13 +421,10 @@ mod tests { fn batching_preserves_the_index_of_an_undecodable_input() { let mut inputs = encrypted_inputs(&[1, 1, 1, 1, 1]); inputs.ciphertexts[3].0 = vec![0xff; 8]; - let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let error = MerkleTreeBuilder::new(5) - .compute_leaf_hashes_batched( - &inputs, - &[], - ¶ms, + let error = input(inputs) + .run_batched( + sum_processor, InputPolicy::default(), Batching::Parallel { batch_size: 2 }, ) @@ -477,6 +446,7 @@ mod tests { let agreeing = PublishedInput { index: 0, ciphertext: &bytes, + ciphertext_hash: [0; 32], commitment: Some(&commitment), metadata: &[], recomputed: Some(commitment), @@ -509,11 +479,10 @@ mod tests { #[test] fn all_inputs_selects_everything() { - let bytes = vec![0u8]; - let entries: Vec = (0..3) - .map(|index| PublishedInput { + let entries: Vec = (0..3) + .map(|index| InputRecord { index, - ciphertext: &bytes, + ciphertext_hash: [0; 32], commitment: None, metadata: &[], recomputed: None, @@ -529,7 +498,7 @@ mod tests { /// when a policy excludes anything and the caller runs the processor itself. #[test] fn the_returned_ciphertext_is_the_one_the_journal_describes() { - fn drop_the_first(inputs: &[PublishedInput]) -> Vec { + fn drop_the_first(inputs: &[InputRecord]) -> Vec { (1..inputs.len()).collect() } @@ -539,12 +508,7 @@ mod tests { select: drop_the_first, }; - let (result, ciphertext) = ComputeInput { - fhe_inputs: inputs.clone(), - published: Vec::new(), - } - .run(sum_processor, policy) - .unwrap(); + let (result, ciphertext) = input(inputs.clone()).run(sum_processor, policy).unwrap(); assert_eq!( result.ciphertext_hash, @@ -554,8 +518,8 @@ mod tests { // And it is genuinely the selected subset, not the whole set. let params = decode_bfv_params_arc(&inputs.params).unwrap(); - let over_everything = sum_processor(&FHEProcessorInput { - ciphertexts: &inputs.ciphertexts, + let over_everything = sum_processor(FHEProcessorInput { + ciphertexts: &mut inputs.ciphertexts.iter().cloned(), params: ¶ms, }); assert_ne!( diff --git a/crates/compute-provider/src/lib.rs b/crates/compute-provider/src/lib.rs index 72c3dd9437..b248f24e69 100644 --- a/crates/compute-provider/src/lib.rs +++ b/crates/compute-provider/src/lib.rs @@ -10,9 +10,11 @@ mod compute_manager; pub mod hashing; mod merkle_tree_builder; pub mod policy; +mod secure_process; pub use ciphertext_output::*; pub use compute_input::*; pub use compute_manager::*; pub use merkle_tree_builder::Batching; -pub use policy::{InputPolicy, PublishedInput}; +pub use policy::{InputPolicy, InputRecord, PublishedInput}; +pub use secure_process::{SecureProcess, Selected}; diff --git a/crates/compute-provider/src/merkle_tree_builder.rs b/crates/compute-provider/src/merkle_tree_builder.rs index b24a9bffa7..273cef2781 100644 --- a/crates/compute-provider/src/merkle_tree_builder.rs +++ b/crates/compute-provider/src/merkle_tree_builder.rs @@ -4,17 +4,13 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::compute_input::{ComputeError, FHEInputs, PublishedData}; -use crate::policy::{InputPolicy, PublishedInput}; +use crate::compute_input::ComputeError; use ark_bn254::Fr; use ark_ff::{BigInt, BigInteger}; -use e3_bfv_client::client::compute_ct_commitment_with_params; -use fhe::bfv::BfvParameters; use light_poseidon::{Poseidon, PoseidonHasher}; use num_bigint::BigUint; use num_traits::Num; use std::str::FromStr; -use std::sync::Arc; use zk_kit_imt::imt::IMT; /// How the per-input ciphertext commitments are computed. @@ -55,153 +51,14 @@ impl MerkleTreeBuilder { /// Sets the leaves directly, for tests that need a known tree. /// /// Never use this to build a tree the journal publishes. A Secure Process must derive its - /// leaves from the ciphertexts it consumed, with [`Self::compute_leaf_hashes_batched`]. Leaves - /// that arrive as a separate value can disagree with those ciphertexts. + /// leaves from the ciphertexts it consumed, as [`crate::SecureProcess`] does. Leaves that arrive + /// as a separate value can disagree with those ciphertexts. #[cfg(test)] pub fn with_leaf_hashes(mut self, leaf_hashes: Vec) -> Self { self.leaf_hashes = leaf_hashes; self } - /// Derives one leaf per published input and returns the ciphertexts the policy selected. - /// - /// Two guarantees hold whatever the policy does, because they are applied here rather than - /// delegated: - /// - /// - **every input contributes a leaf**, so the root covers the whole published set and a - /// policy cannot make the result unpublishable by omitting one; - /// - **leaves are derived from the ciphertexts given**, never accepted alongside them. - /// - /// Test-only. Every production caller reaches [`Self::compute_leaf_hashes_batched`] through - /// `ComputeInput::run_batched`, which threads its own [`Batching`] through. This wrapper keeps - /// the sequential call shape the tests already use. - #[cfg(test)] - pub fn compute_leaf_hashes( - &mut self, - inputs: &FHEInputs, - published: &[PublishedData], - params: &Arc, - policy: InputPolicy, - ) -> Result, u64)>, ComputeError> { - self.compute_leaf_hashes_batched(inputs, published, params, policy, Batching::Sequential) - } - - /// As [`Self::compute_leaf_hashes`], choosing how the commitments are scheduled. - /// - /// Only the commitment recomputation is batched. The policy still sees every entry, in global - /// index order, in one call — so `select` keeps the whole-round view it needs to deduplicate a - /// slot chain or compare inputs against each other, and each leaf keeps its global position. - /// - /// This is the distinction the removed `start_parallel` missed. That version proved each chunk - /// as its own round and fed the chunk results into a final tally with a hardcoded index of - /// zero, so the leaves no longer bound an input to its position. Batching a pure per-input - /// function cannot do that: the inputs, their order, and the tree are unchanged. - pub fn compute_leaf_hashes_batched( - &mut self, - inputs: &FHEInputs, - published: &[PublishedData], - params: &Arc, - policy: InputPolicy, - batching: Batching, - ) -> Result, u64)>, ComputeError> { - let empty = PublishedData::default(); - - let recomputed = Self::recompute_commitments(&inputs.ciphertexts, params, batching); - - let entries: Vec = inputs - .ciphertexts - .iter() - .enumerate() - .map(|(index, (ciphertext, _))| { - let entry = published.get(index).unwrap_or(&empty); - PublishedInput { - index, - ciphertext, - commitment: entry.commitment.as_ref(), - metadata: &entry.metadata, - // Recomputed above rather than by the policy: it is the one value that ties the - // published bytes back to what the E3 program proved, and it needs the BFV - // parameters. A ciphertext that does not deserialize yields `None`, which is an - // unusable input rather than a failure — the bytes are untrusted. - recomputed: recomputed[index], - } - }) - .collect(); - - for entry in &entries { - self.leaf_hashes.push((policy.leaf)(entry)?); - } - - let mut selected = (policy.select)(&entries); - selected.sort_unstable(); - selected.dedup(); - - selected - .into_iter() - .map(|index| { - inputs.ciphertexts.get(index).cloned().ok_or_else(|| { - ComputeError::MerkleTree(format!("selected index {index} is out of range")) - }) - }) - .collect() - } - - /// Recomputes every input's ciphertext commitment, in index order. - /// - /// The one expensive step per input, and pure: it reads the ciphertext bytes and the shared - /// parameters, and nothing else. That is what makes it safe to schedule freely. - #[cfg(feature = "parallel")] - fn recompute_commitments( - ciphertexts: &[(Vec, u64)], - params: &Arc, - batching: Batching, - ) -> Vec> { - use rayon::prelude::*; - - let batch_size = match batching { - Batching::Sequential => 0, - Batching::Parallel { batch_size } => batch_size, - }; - - // A zero or one chunk is the sequential schedule. Taking that path explicitly keeps a - // misconfigured batch size from panicking inside `chunks`. - if batch_size <= 1 { - return ciphertexts - .iter() - .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) - .collect(); - } - - // `flat_map` over ordered chunks, not `par_iter` over inputs: rayon preserves the order of - // an indexed parallel iterator, so the output stays in index order, and chunking bounds how - // many of the large intermediate values are live at once. - ciphertexts - .par_chunks(batch_size) - .flat_map(|chunk| { - chunk - .iter() - .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) - .collect::>() - }) - .collect() - } - - /// The sequential schedule, used when the `parallel` feature is off. - /// - /// [`Batching::Parallel`] is accepted and ignored here. A caller that asks for batching without - /// the feature gets the same commitments, so failing would serve nothing. - #[cfg(not(feature = "parallel"))] - fn recompute_commitments( - ciphertexts: &[(Vec, u64)], - params: &Arc, - _batching: Batching, - ) -> Vec> { - ciphertexts - .iter() - .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) - .collect() - } - fn poseidon_hash(nodes: Vec) -> String { let mut poseidon = Poseidon::::new_circom(2).unwrap(); let mut field_elements = Vec::new(); diff --git a/crates/compute-provider/src/policy.rs b/crates/compute-provider/src/policy.rs index d69d42ae42..2c3a775919 100644 --- a/crates/compute-provider/src/policy.rs +++ b/crates/compute-provider/src/policy.rs @@ -26,12 +26,17 @@ use num_traits::Num; pub const SNARK_SCALAR_FIELD: &str = "21888242871839275222246405745257275088548364400416034343698204186575808495617"; -/// One published input, as the Secure Process sees it. +/// One published input, as the Secure Process sees it while it builds the input's leaf. pub struct PublishedInput<'a> { /// Position in the input set, which is also this leaf's position in the tree. pub index: usize, /// The serialized ciphertext the E3 program published. pub ciphertext: &'a [u8], + /// Keccak-256 of `ciphertext`, computed once by the Secure Process. + /// + /// The second pass checks each selected ciphertext against this digest, so a leaf that binds + /// the bytes can use it instead of hashing them again. + pub ciphertext_hash: [u8; 32], /// The commitment the E3 program stored, when it publishes one. /// /// The proof an E3 program checks at input time typically constrains this and never sees the @@ -53,11 +58,41 @@ impl PublishedInput<'_> { /// `false` when the two disagree or the ciphertext does not deserialize. Always `true` when /// the program publishes no commitment, since there is then nothing to check against. pub fn matches_commitment(&self) -> bool { - match (self.commitment, self.recomputed) { - (Some(stored), Some(recomputed)) => *stored == recomputed, - (Some(_), None) => false, - (None, _) => true, - } + matches_commitment(self.commitment, self.recomputed) + } +} + +/// What selection sees of one published input: everything except the ciphertext bytes. +/// +/// The Secure Process reads the ciphertexts one at a time and keeps none of them, so a round can +/// be larger than the zkVM's memory. Selection runs after every input has been read, when only +/// these values remain. The selected ciphertexts are read again for the computation. +pub struct InputRecord<'a> { + /// Position in the input set, which is also this leaf's position in the tree. + pub index: usize, + /// Keccak-256 of the published ciphertext. + pub ciphertext_hash: [u8; 32], + /// The commitment the E3 program stored, when it publishes one. + pub commitment: Option<&'a [u8; 32]>, + /// Whatever else the E3 program published per input, opaque to this crate. + pub metadata: &'a [u8], + /// The commitment recomputed from the ciphertext, or `None` when it does not deserialize. + pub recomputed: Option<[u8; 32]>, +} + +impl InputRecord<'_> { + /// Whether the published bytes reproduce the commitment the E3 program stored. See + /// [`PublishedInput::matches_commitment`]. + pub fn matches_commitment(&self) -> bool { + matches_commitment(self.commitment, self.recomputed) + } +} + +fn matches_commitment(stored: Option<&[u8; 32]>, recomputed: Option<[u8; 32]>) -> bool { + match (stored, recomputed) { + (Some(stored), Some(recomputed)) => *stored == recomputed, + (Some(_), None) => false, + (None, _) => true, } } @@ -67,8 +102,9 @@ pub type LeafFn = fn(&PublishedInput) -> Result; /// Chooses which inputs the computation runs over, by index. /// /// Must be a function of data the input root binds, or two provers over the same published inputs -/// would disagree and a prover could choose what to leave out. -pub type SelectFn = fn(&[PublishedInput]) -> Vec; +/// would disagree and a prover could choose what to leave out. It sees every input's record but no +/// ciphertext bytes. +pub type SelectFn = fn(&[InputRecord]) -> Vec; /// An E3 program's answers to both questions. #[derive(Clone, Copy)] @@ -104,7 +140,7 @@ pub fn commitment_leaf(input: &PublishedInput) -> Result { } /// Every input is computed over, in published order. -pub fn all_inputs(inputs: &[PublishedInput]) -> Vec { +pub fn all_inputs(inputs: &[InputRecord]) -> Vec { (0..inputs.len()).collect() } diff --git a/crates/compute-provider/src/secure_process.rs b/crates/compute-provider/src/secure_process.rs new file mode 100644 index 0000000000..5ced1dd6e7 --- /dev/null +++ b/crates/compute-provider/src/secure_process.rs @@ -0,0 +1,583 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! The Secure Process over a round that arrives one ciphertext at a time. +//! +//! A round is read twice. The first pass reads every ciphertext in index order and keeps only what +//! the tree and the policy need: the leaf, the recomputed commitment and the hash of the bytes. +//! Selection then runs over those records. The second pass reads the selected ciphertexts again, in +//! index order, and refuses any whose hash differs from the first pass before the processor sees +//! it. +//! +//! Only one ciphertext is held at a time, so a round can be larger than the zkVM guest's memory. +//! A host runs the same code over ciphertexts it already holds (see +//! [`crate::ComputeInput::run_selected`]), which keeps the journal it predicts equal to the one the +//! guest proves. + +use crate::ciphertext_output::ComputeResult; +use crate::compute_input::{ComputeError, FHEProcessor, FHEProcessorInput, PublishedData}; +use crate::hashing::keccak256; +use crate::merkle_tree_builder::{Batching, MerkleTreeBuilder}; +use crate::policy::{InputPolicy, InputRecord, PublishedInput}; +use e3_bfv_client::client::compute_ct_commitment_with_params; +use e3_fhe_params::decode_bfv_params_arc; +use fhe::bfv::BfvParameters; +use std::sync::Arc; + +/// What the first pass keeps of one input once its bytes are gone. +struct Absorbed { + ciphertext_hash: [u8; 32], + recomputed: Option<[u8; 32]>, +} + +/// The first pass: every input of the round, in index order. +pub struct SecureProcess { + params: Arc, + params_hash: [u8; 32], + policy: InputPolicy, + indices: Vec, + published: Vec, + absorbed: Vec, + tree: MerkleTreeBuilder, +} + +impl SecureProcess { + /// Starts a round of `indices.len()` inputs. + /// + /// `indices` holds each input's on-chain index, which the processor receives beside the + /// ciphertext. `published` is empty, or has one entry per input in the same order. + pub fn new( + params: &[u8], + indices: Vec, + published: Vec, + policy: InputPolicy, + ) -> Result { + let decoded = + decode_bfv_params_arc(params).map_err(|e| ComputeError::DecodeParams(e.to_string()))?; + if !published.is_empty() && published.len() != indices.len() { + return Err(ComputeError::MerkleTree(format!( + "{} ciphertexts but {} published entries", + indices.len(), + published.len() + ))); + } + + Ok(Self { + params: decoded, + params_hash: keccak256(params), + policy, + absorbed: Vec::with_capacity(indices.len()), + tree: MerkleTreeBuilder::new(indices.len()), + indices, + published, + }) + } + + /// The decoded BFV parameters. + pub fn params(&self) -> &Arc { + &self.params + } + + /// Reads the next input, in index order. + /// + /// A ciphertext that does not deserialize is recorded as such rather than refused: the bytes + /// are untrusted, and the policy decides what an unusable input means. + pub fn absorb(&mut self, ciphertext: &[u8]) -> Result<(), ComputeError> { + let recomputed = compute_ct_commitment_with_params(ciphertext, &self.params).ok(); + self.absorb_recomputed(ciphertext, recomputed) + } + + /// As [`Self::absorb`], with the commitment of these bytes already recomputed. + /// + /// For a host that recomputes commitments on a thread pool. Not public, because the caller is + /// trusted to pass the commitment of exactly these bytes. + fn absorb_recomputed( + &mut self, + ciphertext: &[u8], + recomputed: Option<[u8; 32]>, + ) -> Result<(), ComputeError> { + let index = self.absorbed.len(); + if index == self.indices.len() { + return Err(ComputeError::InputCount { + expected: self.indices.len(), + actual: index + 1, + }); + } + + let ciphertext_hash = keccak256(ciphertext); + let entry = self.published.get(index); + let leaf = (self.policy.leaf)(&PublishedInput { + index, + ciphertext, + ciphertext_hash, + commitment: entry.and_then(|entry| entry.commitment.as_ref()), + metadata: entry.map_or(&[][..], |entry| entry.metadata.as_slice()), + recomputed, + })?; + + self.tree.leaf_hashes.push(leaf); + self.absorbed.push(Absorbed { + ciphertext_hash, + recomputed, + }); + Ok(()) + } + + /// Ends the first pass: builds the input tree and applies the policy's selection. + pub fn select(self) -> Result { + if self.absorbed.len() != self.indices.len() { + return Err(ComputeError::InputCount { + expected: self.indices.len(), + actual: self.absorbed.len(), + }); + } + + let records: Vec = self + .absorbed + .iter() + .enumerate() + .map(|(index, absorbed)| { + let entry = self.published.get(index); + InputRecord { + index, + ciphertext_hash: absorbed.ciphertext_hash, + commitment: entry.and_then(|entry| entry.commitment.as_ref()), + metadata: entry.map_or(&[][..], |entry| entry.metadata.as_slice()), + recomputed: absorbed.recomputed, + } + }) + .collect(); + let mut selected = (self.policy.select)(&records); + drop(records); + selected.sort_unstable(); + selected.dedup(); + if let Some(&index) = selected.last() { + if index >= self.indices.len() { + return Err(ComputeError::MerkleTree(format!( + "selected index {index} is out of range" + ))); + } + } + + // Every input contributed a leaf above, whatever the policy selected. Dropping one would + // change the root and make the result unpublishable. + let root = self + .tree + .build_tree()? + .root() + .ok_or_else(|| ComputeError::MerkleTree("the tree has no root".into()))?; + let merkle_root = hex::decode(root).map_err(|e| ComputeError::MerkleTree(e.to_string()))?; + + Ok(Selected { + params: self.params, + params_hash: self.params_hash, + merkle_root, + indices: self.indices, + hashes: self + .absorbed + .into_iter() + .map(|absorbed| absorbed.ciphertext_hash) + .collect(), + selected, + }) + } +} + +/// The second pass: the selected inputs, in index order. +pub struct Selected { + params: Arc, + params_hash: [u8; 32], + merkle_root: Vec, + indices: Vec, + hashes: Vec<[u8; 32]>, + selected: Vec, +} + +impl Selected { + /// The inputs the processor runs over, ascending. The second pass reads exactly these, in this + /// order. + pub fn indices(&self) -> &[usize] { + &self.selected + } + + /// Runs the processor over the selected inputs and returns the result and the output + /// ciphertext. + /// + /// `read` returns the ciphertext at the given index. Each is refused unless its hash matches + /// the first pass, so whoever supplies the second pass cannot choose what is computed over. + /// The processor must read every selected input. + pub fn finish( + self, + processor: FHEProcessor, + read: impl FnMut(usize) -> Result, ComputeError>, + ) -> Result<(ComputeResult, Vec), ComputeError> { + let mut ciphertexts = Checked { + selected: self.selected.iter(), + hashes: &self.hashes, + indices: &self.indices, + read, + failure: None, + }; + let output = processor(FHEProcessorInput { + ciphertexts: &mut ciphertexts, + params: &self.params, + }); + if let Some(error) = ciphertexts.failure { + return Err(error); + } + let unread = ciphertexts.selected.len(); + if unread > 0 { + return Err(ComputeError::Unread { remaining: unread }); + } + + let ciphertext_commitment = compute_ct_commitment_with_params(&output, &self.params) + .map_err(|e| ComputeError::OutputCommitment(e.to_string()))? + .to_vec(); + + Ok(( + ComputeResult { + ciphertext_hash: keccak256(&output).to_vec(), + ciphertext_commitment, + params_hash: self.params_hash.to_vec(), + merkle_root: self.merkle_root, + }, + output, + )) + } +} + +/// The selected ciphertexts as the processor reads them, each checked against the first pass. +struct Checked<'a, R> { + selected: std::slice::Iter<'a, usize>, + hashes: &'a [[u8; 32]], + indices: &'a [u64], + read: R, + failure: Option, +} + +impl Iterator for Checked<'_, R> +where + R: FnMut(usize) -> Result, ComputeError>, +{ + type Item = (Vec, u64); + + fn next(&mut self) -> Option { + if self.failure.is_some() { + return None; + } + let index = *self.selected.next()?; + match (self.read)(index) { + Ok(bytes) if keccak256(&bytes) == self.hashes[index] => { + Some((bytes, self.indices[index])) + } + Ok(_) => { + self.failure = Some(ComputeError::InputChanged { index }); + None + } + Err(error) => { + self.failure = Some(error); + None + } + } + } +} + +/// Recomputes every input's ciphertext commitment, in index order. +/// +/// The one expensive step per input, and pure: it reads the ciphertext bytes and the shared +/// parameters, and nothing else. That is what makes it safe to schedule freely. +#[cfg(feature = "parallel")] +pub(crate) fn recompute_commitments( + ciphertexts: &[(Vec, u64)], + params: &Arc, + batching: Batching, +) -> Vec> { + use rayon::prelude::*; + + let batch_size = match batching { + Batching::Sequential => 0, + Batching::Parallel { batch_size } => batch_size, + }; + + // A zero or one chunk is the sequential schedule. Taking that path explicitly keeps a + // misconfigured batch size from panicking inside `chunks`. + if batch_size <= 1 { + return ciphertexts + .iter() + .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) + .collect(); + } + + // `flat_map` over ordered chunks, not `par_iter` over inputs: rayon preserves the order of an + // indexed parallel iterator, so the output stays in index order, and chunking bounds how many + // of the large intermediate values are live at once. + ciphertexts + .par_chunks(batch_size) + .flat_map(|chunk| { + chunk + .iter() + .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) + .collect::>() + }) + .collect() +} + +/// The sequential schedule, used when the `parallel` feature is off. +/// +/// [`Batching::Parallel`] is accepted and ignored here. A caller that asks for batching without +/// the feature gets the same commitments, so failing would serve nothing. +#[cfg(not(feature = "parallel"))] +pub(crate) fn recompute_commitments( + ciphertexts: &[(Vec, u64)], + params: &Arc, + _batching: Batching, +) -> Vec> { + ciphertexts + .iter() + .map(|(bytes, _)| compute_ct_commitment_with_params(bytes, params).ok()) + .collect() +} + +/// Runs the first pass over ciphertexts the caller already holds. +pub(crate) fn absorb_all( + process: &mut SecureProcess, + ciphertexts: &[(Vec, u64)], + batching: Batching, +) -> Result<(), ComputeError> { + let recomputed = recompute_commitments(ciphertexts, process.params(), batching); + for ((bytes, _), recomputed) in ciphertexts.iter().zip(recomputed) { + process.absorb_recomputed(bytes, recomputed)?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::compute_input::{ComputeInput, FHEInputs}; + use crate::policy::leaf_from_digest; + use e3_fhe_params::{build_pair_for_preset, encode_bfv_params, BfvPreset}; + use fhe::bfv::{Ciphertext, Encoding, Plaintext, PublicKey, SecretKey}; + use fhe_traits::{DeserializeParametrized, FheEncoder, FheEncrypter, Serialize}; + use rand::SeedableRng; + use rand_chacha::ChaCha8Rng; + + fn sum(input: FHEProcessorInput<'_>) -> Vec { + let mut sum = Ciphertext::zero(input.params); + for (bytes, _) in input.ciphertexts { + sum += &Ciphertext::from_bytes(&bytes, input.params).unwrap(); + } + sum.to_bytes() + } + + fn first_only(input: FHEProcessorInput<'_>) -> Vec { + let (bytes, _) = input.ciphertexts.next().unwrap(); + Ciphertext::from_bytes(&bytes, input.params) + .unwrap() + .to_bytes() + } + + /// Binds the bytes and accepts an undecodable input, so a round can contain one. + fn hash_leaf(input: &PublishedInput) -> Result { + let mut digest = input.ciphertext_hash.to_vec(); + digest.extend_from_slice(&input.recomputed.unwrap_or_default()); + Ok(leaf_from_digest(&crate::hashing::keccak256(&digest))) + } + + /// Every usable input at an even index. + fn usable_even(inputs: &[InputRecord]) -> Vec { + inputs + .iter() + .filter(|input| input.index % 2 == 0 && input.matches_commitment()) + .map(|input| input.index) + .collect() + } + + const POLICY: InputPolicy = InputPolicy { + leaf: hash_leaf, + select: usable_even, + }; + + /// Seven inputs. Input 4 does not deserialize and input 2's published commitment is wrong, so + /// the policy drops both along with every odd index. + fn round() -> ComputeInput { + let (params, _) = build_pair_for_preset(BfvPreset::InsecureThreshold512).unwrap(); + let mut rng = ChaCha8Rng::seed_from_u64(11); + let secret_key = SecretKey::random(¶ms, &mut rng); + let public_key = PublicKey::new(&secret_key, &mut rng); + + let mut ciphertexts: Vec<(Vec, u64)> = (0..7u64) + .map(|value| { + let plaintext = Plaintext::try_encode(&[value], Encoding::poly(), ¶ms).unwrap(); + let ciphertext = public_key.try_encrypt(&plaintext, &mut rng).unwrap(); + (ciphertext.to_bytes(), 100 + value) + }) + .collect(); + ciphertexts[4].0 = vec![0xff; 16]; + + let mut published: Vec = ciphertexts + .iter() + .map(|(bytes, _)| PublishedData { + commitment: Some( + compute_ct_commitment_with_params(bytes, ¶ms).unwrap_or_default(), + ), + metadata: vec![7; 3], + }) + .collect(); + published[2].commitment = Some([9; 32]); + + ComputeInput { + fhe_inputs: FHEInputs { + ciphertexts, + params: encode_bfv_params(¶ms), + }, + published, + } + } + + fn streamed(input: &ComputeInput) -> SecureProcess { + let mut process = SecureProcess::new( + &input.fhe_inputs.params, + input + .fhe_inputs + .ciphertexts + .iter() + .map(|(_, index)| *index) + .collect(), + input.published.clone(), + POLICY, + ) + .unwrap(); + for (bytes, _) in &input.fhe_inputs.ciphertexts { + process.absorb(bytes).unwrap(); + } + process + } + + /// The guest reads the round one ciphertext at a time and the host holds all of it. Both must + /// reach the same root, selection, output and journal values, or the host predicts a journal + /// the guest never proves. + #[test] + fn a_streamed_round_matches_a_held_round() { + let input = round(); + let (held, held_output, held_selection) = input + .run_selected(sum, POLICY, Batching::Parallel { batch_size: 3 }) + .unwrap(); + assert_eq!(held_selection, vec![0, 6], "inputs 2 and 4 are unusable"); + + let selected = streamed(&input).select().unwrap(); + assert_eq!(selected.indices(), held_selection.as_slice()); + let (streamed, streamed_output) = selected + .finish(sum, |index| { + Ok(input.fhe_inputs.ciphertexts[index].0.clone()) + }) + .unwrap(); + + assert_eq!(streamed.merkle_root, held.merkle_root); + assert_eq!(streamed.ciphertext_hash, held.ciphertext_hash); + assert_eq!(streamed.ciphertext_commitment, held.ciphertext_commitment); + assert_eq!(streamed.params_hash, held.params_hash); + assert_eq!(streamed_output, held_output); + } + + /// Whoever supplies the second pass must not choose what is computed over. A ciphertext that + /// differs from the one hashed in the first pass is refused, even a valid one. + #[test] + fn a_changed_ciphertext_in_the_second_pass_is_refused() { + let input = round(); + let error = streamed(&input) + .select() + .unwrap() + .finish(sum, |index| { + let substitute = if index == 6 { 0 } else { index }; + Ok(input.fhe_inputs.ciphertexts[substitute].0.clone()) + }) + .unwrap_err(); + + assert!( + matches!(error, ComputeError::InputChanged { index: 6 }), + "got {error:?}" + ); + } + + /// A second pass that runs out reports why, rather than computing over what arrived. + #[test] + fn a_failed_second_pass_read_is_reported() { + let input = round(); + let error = streamed(&input) + .select() + .unwrap() + .finish(sum, |index| { + if index == 0 { + Ok(input.fhe_inputs.ciphertexts[0].0.clone()) + } else { + Err(ComputeError::InputCount { + expected: 2, + actual: 1, + }) + } + }) + .unwrap_err(); + + assert!( + matches!(error, ComputeError::InputCount { .. }), + "got {error:?}" + ); + } + + /// The first pass reads every input exactly once. A round with an input missing or added would + /// build a different tree from the one the E3 program stored. + #[test] + fn the_first_pass_reads_every_input_once() { + let input = round(); + + let mut short = SecureProcess::new( + &input.fhe_inputs.params, + vec![0; 7], + input.published.clone(), + POLICY, + ) + .unwrap(); + for (bytes, _) in &input.fhe_inputs.ciphertexts[..6] { + short.absorb(bytes).unwrap(); + } + assert!(matches!( + short.select(), + Err(ComputeError::InputCount { + expected: 7, + actual: 6 + }) + )); + + let mut long = streamed(&input); + assert!(matches!( + long.absorb(&input.fhe_inputs.ciphertexts[0].0), + Err(ComputeError::InputCount { + expected: 7, + actual: 8 + }) + )); + } + + /// The journal describes a computation over the whole selection. A processor that stops early + /// would publish a result over fewer inputs. + #[test] + fn the_processor_must_read_every_selected_input() { + let input = round(); + let error = streamed(&input) + .select() + .unwrap() + .finish(first_only, |index| { + Ok(input.fhe_inputs.ciphertexts[index].0.clone()) + }) + .unwrap_err(); + + assert!( + matches!(error, ComputeError::Unread { remaining: 1 }), + "got {error:?}" + ); + } +} diff --git a/crates/config/src/app_config.rs b/crates/config/src/app_config.rs index 2dc55d4f2e..1958d47dfc 100644 --- a/crates/config/src/app_config.rs +++ b/crates/config/src/app_config.rs @@ -648,7 +648,6 @@ node: program: openvm: - repository: "/deployment/source" prover_bin: "/deployment/bin/interfold-openvm-prover" prover_config: "/deployment/prover.json" @@ -683,9 +682,9 @@ nodes: assert_eq!( config.program().openvm(), Some(&OpenVmConfig { - repository: PathBuf::from("/deployment/source"), - prover_bin: PathBuf::from("/deployment/bin/interfold-openvm-prover"), - prover_config: PathBuf::from("/deployment/prover.json"), + prover_bin: Some(PathBuf::from("/deployment/bin/interfold-openvm-prover")), + prover_config: Some(PathBuf::from("/deployment/prover.json")), + ..OpenVmConfig::default() }) ); assert!(config.peers().is_empty()); diff --git a/crates/config/src/program_config.rs b/crates/config/src/program_config.rs index 11a0ebb4ec..35dd0ce86c 100644 --- a/crates/config/src/program_config.rs +++ b/crates/config/src/program_config.rs @@ -10,13 +10,49 @@ //! execution, not the ciphernode itself. use serde::{Deserialize, Serialize}; +use std::path::PathBuf; -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +/// Which OpenVM worker proves. +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum OpenVmBackend { + /// The CUDA worker when one is configured and can open a GPU, otherwise the CPU worker. + #[default] + Auto, + Cpu, + /// The CUDA worker. The service refuses to start when it cannot open a GPU. + Cuda, +} + +impl OpenVmBackend { + pub fn as_str(&self) -> &'static str { + match self { + Self::Auto => "auto", + Self::Cpu => "cpu", + Self::Cuda => "cuda", + } + } +} + +/// The OpenVM proving service. Every path is absolute and local to the deployment. +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)] #[serde(deny_unknown_fields)] pub struct OpenVmConfig { - pub repository: std::path::PathBuf, - pub prover_bin: std::path::PathBuf, - pub prover_config: std::path::PathBuf, + /// The CPU build of `interfold-openvm-prover`. + #[serde(default)] + pub prover_bin: Option, + /// The CUDA build of `interfold-openvm-prover`. + #[serde(default)] + pub prover_bin_cuda: Option, + #[serde(default)] + pub backend: OpenVmBackend, + /// The worker configuration. Defaults to the one `interfold program compile` writes. + #[serde(default)] + pub prover_config: Option, + /// The directory `cargo openvm setup` wrote the Halo2 key, parameters and verifier to. + /// Defaults to `~/.openvm`. + #[serde(default)] + pub setup_dir: Option, } #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -54,16 +90,17 @@ impl ProgramConfig { #[cfg(test)] mod tests { - use super::ProgramConfig; + use super::{OpenVmBackend, ProgramConfig}; + use std::path::PathBuf; #[test] fn deserializes_openvm_worker_configuration() { let config: ProgramConfig = serde_yaml::from_str( r#" openvm: - repository: "/deployment/source" prover_bin: "/deployment/bin/interfold-openvm-prover" - prover_config: "/deployment/prover.json" + prover_bin_cuda: "/deployment/bin/interfold-openvm-prover-cuda" + backend: cuda "#, ) .expect("program config must deserialize"); @@ -71,11 +108,22 @@ openvm: let openvm = config.openvm().expect("OpenVM config must be present"); assert_eq!( openvm.prover_bin, - std::path::PathBuf::from("/deployment/bin/interfold-openvm-prover") + Some(PathBuf::from("/deployment/bin/interfold-openvm-prover")) ); + assert_eq!(openvm.backend, OpenVmBackend::Cuda); + assert_eq!(openvm.prover_config, None); assert!(!config.dev()); } + /// Without a backend, a GPU is used when there is one. + #[test] + fn the_backend_defaults_to_auto() { + let config: ProgramConfig = + serde_yaml::from_str("openvm:\n prover_bin: /deployment/bin/worker\n").unwrap(); + assert_eq!(config.openvm().unwrap().backend, OpenVmBackend::Auto); + assert!(serde_yaml::from_str::("openvm:\n backend: gpu\n").is_err()); + } + #[test] fn rejects_unknown_backend_configuration() { assert!(serde_yaml::from_str::("unknown_backend: {}").is_err()); diff --git a/crates/init/src/lib.rs b/crates/init/src/lib.rs index 31fc4fd947..618332f2a4 100644 --- a/crates/init/src/lib.rs +++ b/crates/init/src/lib.rs @@ -144,6 +144,13 @@ async fn install_interfold( r"(?m)^e3-compute-provider =.*\n?", &format!("e3-compute-provider = {{ git = \"https://github.com/theinterfold/interfold\", rev = \"{}\" }}\n",commit_hash), ), + // Any other dependency on an Interfold crate, such as the OpenVM guest's. Only + // the source changes, so features on the same line are kept. + Filter::new( + "**/Cargo.toml", + r#"path = "(?:\.\./)+crates/[A-Za-z0-9_-]+""#, + &format!(r#"git = "https://github.com/theinterfold/interfold", rev = "{}""#, commit_hash), + ), ], ) .await @@ -173,6 +180,17 @@ async fn install_interfold( }) .await?; + spinner + .run("Setting up the OpenVM proving service", || async { + copy::copy_with_filters( + &PathBuf::from(TEMP_DIR).join("crates/support-scripts/openvm"), + &cwd.join(".interfold/support/openvm"), + &[], + ) + .await + }) + .await?; + spinner .run("Removing template ignore files...", || async { delete_path(&cwd.join(".gitignore")).await diff --git a/crates/openvm-host/Cargo.toml b/crates/openvm-host/Cargo.toml new file mode 100644 index 0000000000..8c28941657 --- /dev/null +++ b/crates/openvm-host/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "e3-openvm-host" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "E3 - Runs an E3 program's Secure Process natively and proves it with the OpenVM worker" +repository.workspace = true + +[dependencies] +anyhow = { workspace = true } +e3-compute-provider = { workspace = true, features = ["parallel"] } +e3-openvm-types = { workspace = true } +tempfile = { workspace = true } +tokio = { workspace = true } diff --git a/crates/openvm-host/src/lib.rs b/crates/openvm-host/src/lib.rs new file mode 100644 index 0000000000..165e17d07a --- /dev/null +++ b/crates/openvm-host/src/lib.rs @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! Proves an E3 program's Secure Process with the OpenVM worker. +//! +//! The host runs the program natively first, with the same `SecureProcess` the guest runs. That +//! gives it the output ciphertext, the journal the guest must reveal and the inputs the guest reads +//! in its second pass. It then runs the separate worker executable, which proves the guest, checks +//! the proof against that journal and writes a seal. +//! +//! The worker is chosen at startup. A CUDA worker is used when one is configured and can open a +//! GPU; otherwise the CPU worker proves. Every worker run has a deadline, after which the worker is +//! stopped, so a hung proof fails its round instead of holding the service. + +use anyhow::{bail, ensure, Context, Result}; +use e3_compute_provider::{ + Batching, ComputeInput, FHEInputs, FHEProcessor, InputPolicy, PublishedData, +}; +use e3_openvm_types::{write_items, ComputeJournal, GuestHeader}; +pub use e3_openvm_types::{ComputeDomain, JOURNAL_BYTES}; +use std::ffi::OsStr; +use std::fs; +use std::io::BufWriter; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::time::Duration; + +/// The length of the seal the worker writes: version, proof data and the nine journal words. +pub const SEAL_BYTES: usize = 2144; + +/// How long a CUDA worker gets to open a GPU. +const PROBE_TIMEOUT: Duration = Duration::from_secs(60); + +/// Commitments recomputed per thread-pool task. At least 2, or the run is sequential. +const COMMITMENT_BATCH: usize = 4; + +/// Which worker proves. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Backend { + Cpu, + Cuda, +} + +/// The operator's choice of worker. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum BackendChoice { + /// The CUDA worker when one is configured and can open a GPU, otherwise the CPU worker. + #[default] + Auto, + Cpu, + /// The CUDA worker. Startup fails when it cannot open a GPU. + Cuda, +} + +impl FromStr for BackendChoice { + type Err = anyhow::Error; + + fn from_str(value: &str) -> Result { + match value { + "" | "auto" => Ok(Self::Auto), + "cpu" => Ok(Self::Cpu), + "cuda" => Ok(Self::Cuda), + other => bail!("unknown OpenVM backend {other:?}; use auto, cpu or cuda"), + } + } +} + +/// Where the workers and their configuration are, and how long they may run. +#[derive(Clone, Debug)] +pub struct WorkerConfig { + /// The CPU worker, `OPENVM_PROVER_BIN`. + pub cpu: Option, + /// The CUDA worker, `OPENVM_PROVER_BIN_CUDA`. + pub cuda: Option, + /// The worker configuration file, `OPENVM_PROVER_CONFIG`. + pub config: PathBuf, + /// `OPENVM_BACKEND`: `auto` (the default), `cpu` or `cuda`. + pub backend: BackendChoice, + /// `OPENVM_CHECK_TIMEOUT_SECS`, 30 minutes by default. The check loads every proving key. + pub check_timeout: Duration, + /// `OPENVM_PROVE_TIMEOUT_SECS`, 24 hours by default. + pub prove_timeout: Duration, +} + +fn absolute_file(name: &str, value: Option) -> Result> { + let Some(value) = value.filter(|value| !value.is_empty()) else { + return Ok(None); + }; + let path = PathBuf::from(value); + ensure!( + path.is_absolute() && path.is_file(), + "{name} must name an existing absolute file path" + ); + Ok(Some(path)) +} + +fn seconds(name: &str, default: u64) -> Result { + let seconds = match std::env::var(name) { + Ok(value) if !value.is_empty() => value + .parse::() + .with_context(|| format!("{name} must be a whole number of seconds"))?, + _ => default, + }; + ensure!(seconds > 0, "{name} must be greater than zero"); + Ok(Duration::from_secs(seconds)) +} + +impl WorkerConfig { + /// Reads the configuration from the environment the support scripts set. + pub fn from_env() -> Result { + let var = |name: &str| std::env::var(name).ok(); + let config = absolute_file("OPENVM_PROVER_CONFIG", var("OPENVM_PROVER_CONFIG"))? + .context("Set OPENVM_PROVER_CONFIG to the worker configuration file")?; + let worker = Self { + cpu: absolute_file("OPENVM_PROVER_BIN", var("OPENVM_PROVER_BIN"))?, + cuda: absolute_file("OPENVM_PROVER_BIN_CUDA", var("OPENVM_PROVER_BIN_CUDA"))?, + config, + backend: var("OPENVM_BACKEND").unwrap_or_default().parse()?, + check_timeout: seconds("OPENVM_CHECK_TIMEOUT_SECS", 30 * 60)?, + prove_timeout: seconds("OPENVM_PROVE_TIMEOUT_SECS", 24 * 60 * 60)?, + }; + ensure!( + worker.cpu.is_some() || worker.cuda.is_some(), + "Set OPENVM_PROVER_BIN to the CPU worker, OPENVM_PROVER_BIN_CUDA to the CUDA worker, or both" + ); + Ok(worker) + } +} + +/// Runs the worker and waits for it, stopping it at the deadline. +async fn run_worker(worker: &Path, args: &[&OsStr], timeout: Duration, action: &str) -> Result<()> { + let mut child = tokio::process::Command::new(worker) + .args(args) + .kill_on_drop(true) + .spawn() + .with_context(|| format!("cannot start the OpenVM worker {}", worker.display()))?; + match tokio::time::timeout(timeout, child.wait()).await { + Ok(status) => { + let status = status.context("cannot wait for the OpenVM worker")?; + ensure!(status.success(), "OpenVM {action} failed ({status})"); + Ok(()) + } + Err(_) => { + // `kill` also reaps the process, so a stopped worker leaves no zombie behind. + let _ = child.kill().await; + bail!( + "OpenVM {action} did not finish within {} seconds; the worker was stopped", + timeout.as_secs() + ) + } + } +} + +/// Picks the worker for this machine. +async fn select_worker(config: &WorkerConfig) -> Result<(PathBuf, Backend)> { + let cpu = || { + config + .cpu + .clone() + .map(|worker| (worker, Backend::Cpu)) + .context("Set OPENVM_PROVER_BIN to the CPU worker") + }; + let probe = |worker: PathBuf| async move { + run_worker(&worker, &[OsStr::new("probe")], PROBE_TIMEOUT, "GPU probe") + .await + .map(|()| (worker, Backend::Cuda)) + }; + + match config.backend { + BackendChoice::Cpu => cpu(), + BackendChoice::Cuda => { + let worker = config + .cuda + .clone() + .context("OPENVM_BACKEND=cuda needs OPENVM_PROVER_BIN_CUDA")?; + probe(worker) + .await + .context("The CUDA worker cannot use a GPU on this machine") + } + BackendChoice::Auto => match config.cuda.clone() { + None => { + println!("OpenVM: no CUDA worker is configured; proving on the CPU"); + cpu() + } + Some(worker) => match probe(worker).await { + Ok(selected) => Ok(selected), + Err(error) => { + println!( + "OpenVM: the CUDA worker cannot use a GPU ({error:#}); proving on the CPU" + ); + cpu() + } + }, + }, + } +} + +/// The selected worker, checked against its configuration. +#[derive(Clone, Debug)] +pub struct Prover { + worker: PathBuf, + backend: Backend, + config: PathBuf, + prove_timeout: Duration, +} + +impl Prover { + /// Picks the worker and checks it, its keys and its verifier before any work is accepted. + pub async fn start(config: WorkerConfig) -> Result { + let (worker, backend) = select_worker(&config).await?; + println!( + "OpenVM: checking the {backend:?} worker {} and its artifacts", + worker.display() + ); + run_worker( + &worker, + &[OsStr::new("check"), config.config.as_os_str()], + config.check_timeout, + "configuration check", + ) + .await?; + println!("OpenVM: proving with the {backend:?} worker"); + Ok(Self { + worker, + backend, + config: config.config, + prove_timeout: config.prove_timeout, + }) + } + + pub fn backend(&self) -> Backend { + self.backend + } + + /// Proves one round and returns the proof envelope the E3 program verifies and the output + /// ciphertext it publishes. + pub async fn prove( + &self, + inputs: FHEInputs, + published: Vec, + domain: ComputeDomain, + processor: FHEProcessor, + policy: InputPolicy, + ) -> Result<(Vec, Vec)> { + let job = tempfile::Builder::new() + .prefix("interfold-openvm-") + .tempdir() + .context("cannot create the OpenVM job directory")?; + let input_path = job.path().join("input.bin"); + let journal_path = job.path().join("journal.bin"); + let seal_path = job.path().join("seal.bin"); + + let guest_input = input_path.clone(); + let (journal, ciphertext) = tokio::task::spawn_blocking(move || { + run_natively(inputs, published, domain, processor, policy, &guest_input) + }) + .await + .context("the native computation stopped")??; + fs::write(&journal_path, journal.abi_bytes())?; + + run_worker( + &self.worker, + &[ + OsStr::new("prove"), + self.config.as_os_str(), + input_path.as_os_str(), + journal_path.as_os_str(), + seal_path.as_os_str(), + ], + self.prove_timeout, + "proof generation", + ) + .await?; + + let seal = fs::read(&seal_path).context("the OpenVM worker did not write a seal")?; + Ok((encode_compute_proof(&seal, &journal)?, ciphertext)) + } +} + +/// Runs the Secure Process natively and writes the guest's input items. +fn run_natively( + inputs: FHEInputs, + published: Vec, + domain: ComputeDomain, + processor: FHEProcessor, + policy: InputPolicy, + guest_input: &Path, +) -> Result<(ComputeJournal, Vec)> { + let input = ComputeInput { + fhe_inputs: inputs, + published, + }; + let (result, ciphertext, selected) = input + .run_selected( + processor, + policy, + Batching::Parallel { + batch_size: COMMITMENT_BATCH, + }, + ) + .map_err(|error| anyhow::anyhow!("{error}"))?; + let journal = ComputeJournal::new(&domain, &result).map_err(anyhow::Error::msg)?; + + let ComputeInput { + fhe_inputs, + published, + } = input; + let header = GuestHeader { + domain, + params: fhe_inputs.params, + indices: fhe_inputs + .ciphertexts + .iter() + .map(|(_, index)| *index) + .collect(), + published, + } + .encode() + .map_err(anyhow::Error::msg)?; + + // The order the guest reads: the header, every input, then the selected inputs again. + let ciphertexts = &fhe_inputs.ciphertexts; + let items: Vec<&[u8]> = std::iter::once(header.as_slice()) + .chain(ciphertexts.iter().map(|(bytes, _)| bytes.as_slice())) + .chain( + selected + .iter() + .map(|&index| ciphertexts[index].0.as_slice()), + ) + .collect(); + let file = fs::File::create(guest_input).context("cannot write the guest input")?; + write_items(BufWriter::new(file), items.into_iter()).context("cannot write the guest input")?; + + Ok((journal, ciphertext)) +} + +/// Encodes `abi.encode(bytes seal, bytes32 paramsHash, bytes32 inputRoot)`, the envelope the +/// receipt verifier decodes. +pub fn encode_compute_proof(seal: &[u8], journal: &ComputeJournal) -> Result> { + ensure!( + seal.len() == SEAL_BYTES, + "the OpenVM seal must be {SEAL_BYTES} bytes, not {}", + seal.len() + ); + let mut envelope = Vec::with_capacity(128 + SEAL_BYTES.div_ceil(32) * 32); + let mut offset = [0; 32]; + offset[31] = 0x60; + envelope.extend_from_slice(&offset); + envelope.extend_from_slice(&journal.params_hash); + envelope.extend_from_slice(&journal.merkle_root); + let mut length = [0; 32]; + length[24..].copy_from_slice(&(seal.len() as u64).to_be_bytes()); + envelope.extend_from_slice(&length); + envelope.extend_from_slice(seal); + envelope.resize(envelope.len().next_multiple_of(32), 0); + Ok(envelope) +} + +#[cfg(test)] +mod tests { + use super::*; + use e3_compute_provider::ComputeResult; + + fn journal() -> ComputeJournal { + ComputeJournal::new( + &ComputeDomain { + chain_id: 1, + verifying_contract: [2; 20], + e3_id: [3; 32], + encryption_scheme_id: [4; 32], + committee_public_key_hash: [5; 32], + }, + &ComputeResult { + ciphertext_hash: vec![6; 32], + ciphertext_commitment: vec![7; 32], + params_hash: vec![8; 32], + merkle_root: vec![9; 32], + }, + ) + .unwrap() + } + + #[test] + fn the_envelope_carries_the_seal_and_the_hashes_the_verifier_reads() { + let seal = vec![0xaa; SEAL_BYTES]; + let envelope = encode_compute_proof(&seal, &journal()).unwrap(); + + assert_eq!(envelope.len(), 2272); + assert_eq!(envelope[31], 0x60); + assert_eq!(&envelope[32..64], &[8; 32]); + assert_eq!(&envelope[64..96], &[9; 32]); + assert_eq!(&envelope[120..128], &(SEAL_BYTES as u64).to_be_bytes()); + assert_eq!(&envelope[128..], seal.as_slice()); + assert!(encode_compute_proof(&[], &journal()).is_err()); + } + + #[test] + fn the_backend_choice_parses_and_defaults_to_auto() { + assert_eq!("".parse::().unwrap(), BackendChoice::Auto); + assert_eq!( + "auto".parse::().unwrap(), + BackendChoice::Auto + ); + assert_eq!("cpu".parse::().unwrap(), BackendChoice::Cpu); + assert_eq!( + "cuda".parse::().unwrap(), + BackendChoice::Cuda + ); + assert!("gpu".parse::().is_err()); + } + + /// A stand-in worker: a shell script that behaves as the test needs. + #[cfg(unix)] + fn worker(directory: &Path, name: &str, body: &str) -> PathBuf { + use std::os::unix::fs::PermissionsExt; + let path = directory.join(name); + fs::write(&path, format!("#!/bin/sh\n{body}\n")).unwrap(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o755)).unwrap(); + path + } + + #[cfg(unix)] + fn config(directory: &Path, cpu: Option, cuda: Option) -> WorkerConfig { + WorkerConfig { + cpu, + cuda, + config: directory.join("prover.json"), + backend: BackendChoice::Auto, + check_timeout: Duration::from_secs(5), + prove_timeout: Duration::from_secs(5), + } + } + + /// A machine without a usable GPU proves on the CPU, and one with a GPU uses it. + #[cfg(unix)] + #[tokio::test] + async fn auto_uses_the_gpu_only_when_the_probe_passes() { + let directory = tempfile::tempdir().unwrap(); + let cpu = worker(directory.path(), "cpu", "exit 0"); + let no_gpu = worker( + directory.path(), + "cuda-without-gpu", + "[ \"$1\" = probe ] && exit 1; exit 0", + ); + let gpu = worker(directory.path(), "cuda", "exit 0"); + + let without = config(directory.path(), Some(cpu.clone()), Some(no_gpu)); + assert_eq!( + select_worker(&without).await.unwrap(), + (cpu.clone(), Backend::Cpu) + ); + + let with = config(directory.path(), Some(cpu.clone()), Some(gpu.clone())); + assert_eq!(select_worker(&with).await.unwrap(), (gpu, Backend::Cuda)); + + let cpu_only = config(directory.path(), Some(cpu.clone()), None); + assert_eq!(select_worker(&cpu_only).await.unwrap(), (cpu, Backend::Cpu)); + } + + /// Forcing CUDA on a machine without a GPU is a startup error, not a silent CPU fallback. + #[cfg(unix)] + #[tokio::test] + async fn forced_cuda_without_a_gpu_fails() { + let directory = tempfile::tempdir().unwrap(); + let no_gpu = worker(directory.path(), "cuda", "exit 1"); + let mut forced = config(directory.path(), None, Some(no_gpu)); + forced.backend = BackendChoice::Cuda; + assert!(select_worker(&forced).await.is_err()); + } + + /// A worker that hangs is stopped at the deadline, so the round fails instead of holding the + /// service's only slot. + #[cfg(unix)] + #[tokio::test] + async fn a_hung_worker_is_stopped_at_the_deadline() { + let directory = tempfile::tempdir().unwrap(); + let hung = worker(directory.path(), "hung", "sleep 30"); + let started = std::time::Instant::now(); + + let error = run_worker(&hung, &[], Duration::from_millis(300), "proof generation") + .await + .unwrap_err(); + + assert!(error.to_string().contains("did not finish"), "{error}"); + assert!(started.elapsed() < Duration::from_secs(10)); + } +} diff --git a/crates/support/openvm/prover/Cargo.lock b/crates/openvm-prover/Cargo.lock similarity index 100% rename from crates/support/openvm/prover/Cargo.lock rename to crates/openvm-prover/Cargo.lock diff --git a/crates/support/openvm/prover/Cargo.toml b/crates/openvm-prover/Cargo.toml similarity index 69% rename from crates/support/openvm/prover/Cargo.toml rename to crates/openvm-prover/Cargo.toml index a36d46440c..09242437de 100644 --- a/crates/support/openvm/prover/Cargo.toml +++ b/crates/openvm-prover/Cargo.toml @@ -8,12 +8,14 @@ license = "LGPL-3.0-only" resolver = "3" [features] -cuda = ["openvm-sdk/cuda"] +cuda = ["openvm-sdk/cuda", "dep:openvm-cuda-common"] [dependencies] openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", default-features = false, features = ["parallel", "evm-verify"] } openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +# The CUDA build's `probe` opens a device with it. The same revision the SDK's CUDA backend uses. +openvm-cuda-common = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.1", optional = true } sha2 = "=0.10.9" eyre = "0.6" serde = { version = "1", features = ["derive"] } diff --git a/crates/openvm-prover/README.md b/crates/openvm-prover/README.md new file mode 100644 index 0000000000..a58ed3a350 --- /dev/null +++ b/crates/openvm-prover/README.md @@ -0,0 +1,198 @@ +# OpenVM proving + +OpenVM replaces RISC Zero and Boundless. Each project proves its own E3 program: the guest and the +proving service link the project's `program/` crate, so the guest, the native host and the contract +use one processor and one input policy. This is a new guest and verifier deployment, not an upgrade +of an existing receipt. Existing deployment records and legacy RISC Zero contracts stay unchanged. + +## Pieces + +| Piece | What it is | +| ---------------------------------------- | -------------------------------------------------------------------------- | +| `guest/` in the project | The OpenVM guest. Its own workspace, built with `cargo openvm` | +| `.interfold/support/openvm/service` | The proving service: `e3-program-server` with `e3-openvm-host` as runner | +| `.interfold/support/openvm/compile` | Builds the guest, keys, receipt identity, worker configuration and service | +| `.interfold/support/openvm/start` | Starts the service | +| `interfold-openvm-prover` (this crate) | The worker. A separate process, in a CPU build and a CUDA build | + +`interfold init` copies the service folder and pins the guest's Interfold crates to the template's +commit. In this repository, `templates/default` and `examples/CRISP` link the folder from +`crates/support-scripts/openvm`. + +The guest reads the round one item at a time: a header, every ciphertext in index order, then the +ciphertexts the policy selected, again in index order. It keeps a hash of each ciphertext from the +first pass and refuses a second-pass ciphertext that differs. Only one ciphertext is in guest memory +at a time, so the guest's 512 MiB does not bound the round. The worker holds the whole input stream +twice, about eight times the round's binary size, and the request body limit applies to the +hex-encoded round. + +## Prerequisites + +- Rust 1.91.1, and `cargo-openvm` v2.0.2 with its guest toolchain: + `cargo install --locked --git https://github.com/openvm-org/openvm.git --tag v2.0.2 cargo-openvm`. +- The Halo2 proving key, KZG parameters and EVM verifier from `cargo openvm setup`, in `~/.openvm` + by default. Verify their provenance and checksums before use. +- For a GPU: the CUDA toolkit and driver, and `nvcc` on `PATH` when building the CUDA worker. + +## Build the workers + +From the repository root: + +```sh +pnpm openvm prover-build # CPU: target/openvm/prover/release/interfold-openvm-prover +CARGO_TARGET_DIR=target/openvm/prover-cuda \ + pnpm openvm prover-build --features cuda # CUDA build, in its own target directory +``` + +The CUDA build links the CUDA runtime dynamically, so it starts only where the CUDA libraries are +installed. Keep the two builds apart; a project may configure both. + +## Configure the project + +In `interfold.config.yaml`, with absolute paths local to the machine: + +```yaml +program: + dev: false + openvm: + prover_bin: /opt/openvm/interfold-openvm-prover # the CPU worker + prover_bin_cuda: /opt/openvm/interfold-openvm-prover-cuda # optional + backend: auto # auto, cpu or cuda + # setup_dir: /home/me/.openvm # what `cargo openvm setup` wrote + # prover_config: /path/to/prover.json # defaults to the one `compile` writes +``` + +With `backend: auto` the service runs the CUDA worker's `probe` at startup. When that opens a GPU, +the CUDA worker proves; when there is no CUDA worker, no GPU, or no driver, the CPU worker proves and +the service logs why. `backend: cuda` refuses to start without a working GPU, and `backend: cpu` +never tries one. + +## Compile, deploy and start + +```sh +interfold program compile +``` + +This builds `guest/`, generates its application key, runs the worker's `prepare` for the aggregation +key and receipt identity, writes `.interfold/caches/openvm/prover.json`, and builds the service. The +keys are regenerated only when the guest executable or `guest/openvm.toml` changes. The receipt +identity is in `.interfold/caches/openvm/prepared/identity.json`. + +Deploy the contracts next. The template and CRISP deploys read the identity and verifier artifact +from that `prover.json` unless `OPENVM_APP_EXE_COMMIT`, `OPENVM_APP_VM_COMMIT`, and either +`OPENVM_VERIFIER_ARTIFACT` with `OPENVM_VERIFIER_SHA256` or `OPENVM_HALO2_VERIFIER` with +`OPENVM_HALO2_RUNTIME_CODE_HASH` are set. A rebuilt guest has a new identity and needs a new +verifier. + +```sh +interfold program start +``` + +The service picks its worker, then runs the worker's `check`. That loads the application, +aggregation and Halo2 keys and both KZG parameter files, verifies the verifier artifact's digest, and +recomputes the identity from the executable, before any request is accepted. + +## Worker commands + +| Command | Purpose | +| ------------------------------------------------------------------------------ | ------------------------------------------ | +| `prepare ` | Aggregation key and `identity.json` | +| `write-config ` | The configuration below | +| `probe` | Succeeds only for a CUDA build with a GPU | +| `check ` | Loads and checks every artifact | +| `prove ` | Proves and verifies one round | +| `verify ` | Verifies an existing proof | + +`prove` reads the guest input items the host wrote, proves the application, aggregates it, generates +the Halo2 EVM proof, and verifies it with the configured EVM verifier against the expected journal +and both application commitments before it writes a seal. There is no fake-proof mode. + +| Configuration field | Value | +| ---------------------- | ------------------------------------------------------------- | +| `app_pk` | The guest application proving key | +| `executable` | The guest VM executable | +| `aggregation_pk` | The aggregation key from `prepare` | +| `halo2_pk` | The Halo2 proving key | +| `halo2_params_dir` | The KZG parameter directory | +| `verifier_artifact` | The EVM verifier bytecode JSON | +| `verifier_sha256` | Its SHA-256 digest, lowercase hexadecimal | +| `app_commit` | The `app_commit` object from `identity.json` | +| `segment_memory_bytes` | The proving segment memory limit (`compile` defaults to 8 GiB) | + +## Service settings + +| Variable | Default | Meaning | +| ----------------------------- | ------------------- | --------------------------------------------- | +| `OPENVM_BIND_ADDR` | `127.0.0.1:13151` | Listener | +| `OPENVM_MAX_REQUEST_BYTES` | 128 MiB | Largest `/run_compute` body | +| `MAX_CONCURRENT_COMPUTATIONS` | 1 | Rounds proved at once | +| `OPENVM_CHECK_TIMEOUT_SECS` | 1800 | Deadline for the startup `check` | +| `OPENVM_PROVE_TIMEOUT_SECS` | 86400 | Deadline for one proof; the worker is stopped | + +A request is admitted before its body is read, and a request beyond capacity gets 429. Jobs are in +memory: a restart loses accepted jobs, and operators must reconcile them. Callbacks are retried with +backoff on server errors, timeouts and rate limits. Run the service behind authenticated admission +control, and do not expose it to the Internet. + +`POST /run_compute` and the callback formats are those of the development runner. The proof envelope +is `abi.encode(bytes seal, bytes32 paramsHash, bytes32 inputRoot)`. + +## Receipt format + +The guest reveals SHA-256 of nine consecutive 32-byte ABI words: + +1. Chain ID +2. Interfold address +3. Full uint256 E3 ID +4. Encryption scheme ID +5. Committee public-key hash +6. Ciphertext output hash +7. SAFE ciphertext commitment +8. Parameter hash +9. Input root + +The seal is `abi.encode(uint8(1), bytes(halo2ProofData), bytes32[9](journalWords))`, 2,144 bytes. + +The receipt identity binds the Halo2 verifier address, the executable commitment and the VM +commitment. The protocol BFV verifier and the program's verifier must use the same identity, and +both verification calls stay mandatory. Rounds keep their request-time verifier snapshot and must +drain before a live migration. The historical RISC Zero activation scripts do not activate OpenVM. +The compute path is unaudited. + +## CRISP checks + +From the repository root: + +```sh +pnpm openvm service-test # host, types, Secure Process and program server +pnpm openvm contract-test # receipt and journal contracts +``` + +`pnpm openvm proof-test` verifies an externally supplied proof on an in-memory chain. It needs +`OPENVM_TEST_IDENTITY`, `OPENVM_TEST_JOURNAL`, `OPENVM_TEST_VERIFIER`, `OPENVM_TEST_VERIFIER_SHA256`, +and `OPENVM_TEST_PROOF` (proof JSON) or `OPENVM_TEST_SEAL` (worker seal). + +`pnpm openvm service-e2e` runs a live round: CRISP input submission and indexing, the running +OpenVM service, the callback, and ciphertext publication. It needs an isolated loopback RPC with +chain ID 31337 (use Anvil for long rounds) and a running service started with +`pnpm openvm service-start` after `pnpm openvm compile`. Build the CRISP server with +`pnpm openvm crisp-server-build --release` and generate secure-8192 ballots with +`pnpm openvm fixture `. Set: + +| Variable | Meaning | +| ----------------------------- | ---------------------------------------------------------- | +| `LOCAL_RPC_URL` | Isolated loopback EVM RPC | +| `OPENVM_E2E_FIXTURE` | Directory the fixture command wrote | +| `OPENVM_E2E_SERVER` | Absolute path to the CRISP server binary | +| `OPENVM_E2E_OUTPUT` | New directory for the report and logs | +| `OPENVM_E2E_PROGRAM_URL` | The running service, reachable from CRISP | +| `OPENVM_E2E_CALLBACK_URL` | CRISP URL reachable from the service | +| `OPENVM_E2E_LOCAL_SERVER_URL` | Local CRISP listener; defaults to `http://127.0.0.1:14000` | +| `OPENVM_TEST_IDENTITY` | The `identity.json` the worker was prepared with | +| `OPENVM_TEST_VERIFIER` | The verifier bytecode JSON the worker uses | +| `OPENVM_TEST_VERIFIER_SHA256` | Its SHA-256 digest | + +The test deploys real OpenVM receipt and protocol verifiers, rejects a changed proof, and checks the +tally and settlement. Randomness, DKG proofs, ballot proofs and census, data availability, and +threshold-decryption proofs are local mocks, so it is a real compute-proof test, not a fully +cryptographic E3 round. Keep reports, inputs, keys and proofs out of the repository. diff --git a/crates/support/openvm/prover/src/main.rs b/crates/openvm-prover/src/main.rs similarity index 53% rename from crates/support/openvm/prover/src/main.rs rename to crates/openvm-prover/src/main.rs index 5de7c1054d..d2b27c5fbe 100644 --- a/crates/support/openvm/prover/src/main.rs +++ b/crates/openvm-prover/src/main.rs @@ -1,24 +1,44 @@ // SPDX-License-Identifier: LGPL-3.0-only +//! The OpenVM worker. It proves an E3 program's guest, checks the proof against the journal the +//! host expects, and writes a seal. It runs as its own process so a failed proof cannot take the +//! service down, and so one service can choose between a CPU and a CUDA build of it. +//! +//! - `prepare `: the aggregation key and the receipt identity. +//! - `write-config `: +//! the configuration every other action reads. +//! - `probe`: succeeds when this build can use a GPU on this machine. +//! - `check `: loads every key and the verifier, before a service accepts work. +//! - `prove `: proves and verifies a round. +//! - `verify `: verifies an existing proof. + use eyre::{ensure, Result}; use openvm_circuit::arch::instructions::exe::VmExe; use openvm_sdk::{ config::AggregationSystemParams, - fs::{read_halo2_pk_from_file, read_object_from_file, write_object_to_file}, + fs::{ + read_halo2_pk_from_file, read_object_from_file, write_object_to_file, + EVM_VERIFIER_ARTIFACT_FILENAME, + }, + halo2_params::CacheHalo2ParamsReader, keygen::{AggProvingKey, AppProvingKey}, + prover::Halo2Prover, types::{AppExecutionCommit, EvmHalo2Verifier, EvmProof}, - Sdk, StdIn, F, + Sdk, StdIn, F, OPENVM_VERSION, }; use openvm_sdk_config::SdkVmConfig; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{ fs, - io::{Read, Write}, + io::{BufReader, Read, Write}, path::{Path, PathBuf}, }; -#[derive(Deserialize)] +/// The largest single item the guest reads. Matches `e3_openvm_types::MAX_ITEM_BYTES`. +const MAX_ITEM_BYTES: u64 = 512 * 1024 * 1024 - 16; + +#[derive(Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Config { app_pk: PathBuf, @@ -41,8 +61,7 @@ fn read_limited(path: &Path, limit: usize) -> Result> { Ok(bytes) } -fn config(path: &Path) -> Result { - let config: Config = serde_json::from_slice(&read_limited(path, 64 * 1024)?)?; +fn validate(config: &Config) -> Result<()> { for path in [ &config.app_pk, &config.executable, @@ -52,7 +71,8 @@ fn config(path: &Path) -> Result { ] { ensure!( path.is_absolute() && path.is_file(), - "Each artifact path must name an existing absolute file path" + "Each artifact path must name an existing absolute file path: {}", + path.display() ); } ensure!( @@ -63,6 +83,12 @@ fn config(path: &Path) -> Result { config.segment_memory_bytes > 0, "Set a nonzero segment memory limit" ); + Ok(()) +} + +fn config(path: &Path) -> Result { + let config: Config = serde_json::from_slice(&read_limited(path, 64 * 1024)?)?; + validate(&config)?; Ok(config) } @@ -161,11 +187,112 @@ fn seal(proof: &EvmProof, journal: &[u8]) -> Vec { bytes } +/// Reads the guest's input items, which the host writes with `e3_openvm_types::write_items`: a +/// little-endian `u32` count, then each item as a little-endian `u64` length and its bytes. +/// +/// Each item becomes one entry of the guest's input stream, which the guest reads with +/// `openvm::io::read_vec`. Items are converted as they are read, so the raw file is never held +/// whole. +fn read_items(reader: impl Read) -> Result { + let mut reader = BufReader::new(reader); + let mut word = [0; 4]; + reader.read_exact(&mut word)?; + let count = u32::from_le_bytes(word); + let mut stdin = StdIn::default(); + for _ in 0..count { + let mut length = [0; 8]; + reader.read_exact(&mut length)?; + let length = u64::from_le_bytes(length); + ensure!( + length <= MAX_ITEM_BYTES, + "A guest input item exceeds the guest memory limit" + ); + let mut item = vec![0; length as usize]; + reader.read_exact(&mut item)?; + stdin.write_bytes(&item); + } + ensure!( + reader.read(&mut [0; 1])? == 0, + "Unexpected bytes after the last guest input item" + ); + Ok(stdin) +} + +/// Whether this build can use a GPU here. A CUDA build opens the current device; a CPU build +/// always fails, so a service never mistakes it for a GPU worker. +#[cfg(feature = "cuda")] +fn probe() -> Result<()> { + let device = openvm_cuda_common::common::set_device() + .map_err(|error| eyre::eyre!("Cannot open a CUDA device: {error}"))?; + eprintln!("OpenVM: CUDA device {device} is available"); + Ok(()) +} + +#[cfg(not(feature = "cuda"))] +fn probe() -> Result<()> { + eyre::bail!("This worker was built without CUDA") +} + +fn absolute(path: &Path) -> Result { + fs::canonicalize(path) + .map_err(|error| eyre::eyre!("Cannot resolve {}: {error}", path.display())) +} + +/// Writes the configuration for the keys `prepare` made and the artifacts `cargo openvm setup` +/// downloaded. +fn write_config(paths: &[PathBuf]) -> Result<()> { + ensure!( + paths.len() == 6, + "Expected the output path, app.pk, the executable, the prepared directory, the setup \ + directory, and the segment memory limit" + ); + let prepared = absolute(&paths[3])?; + let setup = absolute(&paths[4])?; + let identity: serde_json::Value = + serde_json::from_slice(&read_limited(&prepared.join("identity.json"), 64 * 1024)?)?; + let verifier_artifact = setup + .join("halo2") + .join("src") + .join(format!("v{OPENVM_VERSION}-base")) + .join(EVM_VERIFIER_ARTIFACT_FILENAME); + let config = Config { + app_pk: absolute(&paths[1])?, + executable: absolute(&paths[2])?, + aggregation_pk: prepared.join("aggregation.pk"), + halo2_pk: setup.join("halo2.pk"), + halo2_params_dir: setup.join("params"), + verifier_sha256: hex::encode(Sha256::digest(read_limited( + &verifier_artifact, + 256 * 1024, + )?)), + verifier_artifact, + app_commit: serde_json::from_value(identity["app_commit"].clone())?, + segment_memory_bytes: paths[5] + .to_str() + .and_then(|value| value.parse().ok()) + .ok_or_else(|| eyre::eyre!("The segment memory limit must be a number of bytes"))?, + }; + validate(&config)?; + + let output = &paths[0]; + let partial = output.with_extension("json.partial"); + fs::write(&partial, serde_json::to_vec_pretty(&config)?)?; + fs::rename(&partial, output)?; + Ok(()) +} + fn main() -> Result<()> { let mut args = std::env::args_os().skip(1); - let action = args - .next() - .ok_or_else(|| eyre::eyre!("Expected prepare, check, prove, or verify"))?; + let action = args.next().ok_or_else(|| { + eyre::eyre!("Expected prepare, write-config, probe, check, prove, or verify") + })?; + if action == "probe" { + ensure!(args.next().is_none(), "Unexpected arguments"); + return probe(); + } + if action == "write-config" { + return write_config(&args.map(PathBuf::from).collect::>()); + } if action == "prepare" { let paths: Vec = args.map(PathBuf::from).collect(); ensure!( @@ -203,11 +330,18 @@ fn main() -> Result<()> { if action == "check" { ensure!(args.next().is_none(), "Unexpected arguments"); sdk(&config)?; + // Load the Halo2 key and both KZG parameter files now. `prove` reads them only after the + // application proof and aggregation, which can take hours. + Halo2Prover::new( + &CacheHalo2ParamsReader::new(&config.halo2_params_dir), + read_halo2_pk_from_file(&config.halo2_pk)?, + ); + eprintln!("OpenVM: the keys, parameters, verifier, and identity are consistent"); return Ok(()); } ensure!( action == "prove" || action == "verify", - "Expected prepare, check, prove, or verify" + "Expected prepare, write-config, probe, check, prove, or verify" ); let paths: Vec = args.map(PathBuf::from).collect(); ensure!( @@ -220,13 +354,10 @@ fn main() -> Result<()> { let proof: EvmProof = if action == "verify" { serde_json::from_slice(&read_limited(&paths[0], 256 * 1024)?)? } else { - let input = read_limited(&paths[0], 512 * 1024 * 1024 - 16)?; + let input = read_items(fs::File::open(&paths[0])?)?; let (sdk, exe) = sdk(&config)?; eprintln!("OpenVM: proving the application"); - let app_proof = sdk - .app_prover(exe.clone())? - .prove(StdIn::from_bytes(&input))?; - drop(input); + let app_proof = sdk.app_prover(exe.clone())?.prove(input)?; eprintln!("OpenVM: aggregating the application proof"); let (stark_proof, mut metadata) = sdk.agg_prover().prove_vm(app_proof)?; let baseline = sdk.prover(exe.clone())?.generate_baseline(); @@ -254,3 +385,47 @@ fn main() -> Result<()> { eprintln!("OpenVM: verified the proof, application identity, and all nine journal words"); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + /// The bytes `e3_openvm_types::write_items` writes for the items `[1, 2, 3]` and `[]`. The same + /// vector is pinned on the writer's side, so a format change on either side fails a test. + const TWO_ITEMS: [u8; 23] = [ + 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + + #[test] + fn reads_each_item_into_its_own_stream_entry() { + let mut expected = StdIn::default(); + expected.write_bytes(&[1, 2, 3]); + expected.write_bytes(&[]); + + let mut stdin = read_items(TWO_ITEMS.as_slice()).unwrap(); + assert_eq!(stdin.read(), expected.read()); + assert_eq!(stdin.read(), expected.read()); + assert!(stdin.read().is_none()); + } + + #[test] + fn refuses_truncated_and_padded_input() { + assert!(read_items(&TWO_ITEMS[..TWO_ITEMS.len() - 1]).is_err()); + let mut padded = TWO_ITEMS.to_vec(); + padded.push(0); + assert!(read_items(padded.as_slice()).is_err()); + } + + #[test] + fn refuses_an_item_above_the_guest_memory_limit() { + let mut input = 1u32.to_le_bytes().to_vec(); + input.extend_from_slice(&(MAX_ITEM_BYTES + 1).to_le_bytes()); + assert!(read_items(input.as_slice()).is_err()); + } + + #[cfg(not(feature = "cuda"))] + #[test] + fn a_cpu_build_never_passes_the_gpu_probe() { + assert!(probe().is_err()); + } +} diff --git a/crates/openvm-types/Cargo.toml b/crates/openvm-types/Cargo.toml new file mode 100644 index 0000000000..3533c14903 --- /dev/null +++ b/crates/openvm-types/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "e3-openvm-types" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "E3 - OpenVM guest input, journal and worker framing" +repository.workspace = true + +[dependencies] +bincode = { workspace = true } +e3-compute-provider = { workspace = true } +serde = { workspace = true } diff --git a/crates/openvm-types/src/lib.rs b/crates/openvm-types/src/lib.rs new file mode 100644 index 0000000000..b095e81d91 --- /dev/null +++ b/crates/openvm-types/src/lib.rs @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! What the OpenVM guest reads and reveals, shared by the guest, the host and the worker. +//! +//! The guest reads a round as a sequence of items: a [`GuestHeader`], then every ciphertext in +//! index order, then the selected ciphertexts in index order (see `e3_compute_provider::SecureProcess`). +//! It reveals the SHA-256 digest of the nine-word [`ComputeJournal`]. + +use bincode::Options; +use e3_compute_provider::{ComputeResult, PublishedData}; +use serde::{Deserialize, Serialize}; +use std::io::{self, Read, Write}; + +/// The largest single item the guest reads. +/// +/// The guest reads each item into memory whole, and its address space is 512 MiB. The bound applies +/// to each item rather than to the round, because the round is read one item at a time. +pub const MAX_ITEM_BYTES: usize = 512 * 1024 * 1024 - 16; + +/// The length of the journal: nine 32-byte ABI words. +pub const JOURNAL_BYTES: usize = 9 * 32; + +/// The E3 a computation belongs to. Every field is revealed in the journal. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct ComputeDomain { + pub chain_id: u64, + pub verifying_contract: [u8; 20], + pub e3_id: [u8; 32], + pub encryption_scheme_id: [u8; 32], + pub committee_public_key_hash: [u8; 32], +} + +/// The first item the guest reads: everything about the round except the ciphertexts. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GuestHeader { + pub domain: ComputeDomain, + /// The encoded BFV parameters. + pub params: Vec, + /// Each input's on-chain index, in tree order. Its length is the round's input count. + pub indices: Vec, + /// What the E3 program published with each input: empty, or one entry per input. + pub published: Vec, +} + +fn header_options() -> impl Options { + bincode::DefaultOptions::new() + .with_fixint_encoding() + .with_limit(MAX_ITEM_BYTES as u64) + .reject_trailing_bytes() +} + +impl GuestHeader { + pub fn encode(&self) -> Result, String> { + header_options() + .serialize(self) + .map_err(|error| format!("cannot encode the guest header: {error}")) + } + + pub fn decode(bytes: &[u8]) -> Result { + header_options() + .deserialize(bytes) + .map_err(|error| format!("invalid guest header: {error}")) + } +} + +/// The nine words the guest reveals, as the receipt verifier reads them. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ComputeJournal { + pub chain_id: [u8; 32], + pub verifying_contract: [u8; 32], + pub e3_id: [u8; 32], + pub encryption_scheme_id: [u8; 32], + pub committee_public_key_hash: [u8; 32], + pub ciphertext_hash: [u8; 32], + pub ciphertext_commitment: [u8; 32], + pub params_hash: [u8; 32], + pub merkle_root: [u8; 32], +} + +fn word(value: &[u8], name: &str) -> Result<[u8; 32], String> { + value + .try_into() + .map_err(|_| format!("the {name} must be 32 bytes")) +} + +impl ComputeJournal { + pub fn new(domain: &ComputeDomain, result: &ComputeResult) -> Result { + let mut chain_id = [0; 32]; + chain_id[24..].copy_from_slice(&domain.chain_id.to_be_bytes()); + let mut verifying_contract = [0; 32]; + verifying_contract[12..].copy_from_slice(&domain.verifying_contract); + + Ok(Self { + chain_id, + verifying_contract, + e3_id: domain.e3_id, + encryption_scheme_id: domain.encryption_scheme_id, + committee_public_key_hash: domain.committee_public_key_hash, + ciphertext_hash: word(&result.ciphertext_hash, "ciphertext hash")?, + ciphertext_commitment: word(&result.ciphertext_commitment, "ciphertext commitment")?, + params_hash: word(&result.params_hash, "parameter hash")?, + merkle_root: word(&result.merkle_root, "input root")?, + }) + } + + /// The nine words in order, as Solidity ABI-encodes them. + pub fn abi_bytes(&self) -> Vec { + [ + self.chain_id, + self.verifying_contract, + self.e3_id, + self.encryption_scheme_id, + self.committee_public_key_hash, + self.ciphertext_hash, + self.ciphertext_commitment, + self.params_hash, + self.merkle_root, + ] + .concat() + } +} + +/// Writes the guest's input items for the worker: a little-endian `u32` item count, then each item +/// as a little-endian `u64` length followed by its bytes. +pub fn write_items<'a, W: Write>( + mut writer: W, + items: impl ExactSizeIterator, +) -> io::Result<()> { + let count = u32::try_from(items.len()) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "too many guest input items"))?; + writer.write_all(&count.to_le_bytes())?; + for item in items { + if item.len() > MAX_ITEM_BYTES { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "a guest input item exceeds the guest memory limit", + )); + } + writer.write_all(&(item.len() as u64).to_le_bytes())?; + writer.write_all(item)?; + } + writer.flush() +} + +/// Reads the items [`write_items`] wrote, one at a time, so a reader never holds more than one. +pub struct ItemReader { + reader: R, + remaining: u32, +} + +impl ItemReader { + pub fn new(mut reader: R) -> io::Result { + let mut count = [0; 4]; + reader.read_exact(&mut count)?; + Ok(Self { + reader, + remaining: u32::from_le_bytes(count), + }) + } + + /// The items not yet read. + pub fn remaining(&self) -> usize { + self.remaining as usize + } + + /// Reads the next item, or `None` after the last. Trailing bytes after the last item are an + /// error, because they mean the file is not the one the host wrote. + pub fn next_item(&mut self) -> io::Result>> { + if self.remaining == 0 { + let mut trailing = [0; 1]; + return match self.reader.read(&mut trailing)? { + 0 => Ok(None), + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + "unexpected bytes after the last guest input item", + )), + }; + } + let mut length = [0; 8]; + self.reader.read_exact(&mut length)?; + let length = u64::from_le_bytes(length); + if length > MAX_ITEM_BYTES as u64 { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "a guest input item exceeds the guest memory limit", + )); + } + let mut item = vec![0; length as usize]; + self.reader.read_exact(&mut item)?; + self.remaining -= 1; + Ok(Some(item)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn domain() -> ComputeDomain { + ComputeDomain { + chain_id: 1, + verifying_contract: [2; 20], + e3_id: [3; 32], + encryption_scheme_id: [4; 32], + committee_public_key_hash: [5; 32], + } + } + + #[test] + fn the_journal_is_nine_words_in_verifier_order() { + let result = ComputeResult { + ciphertext_hash: vec![6; 32], + ciphertext_commitment: vec![7; 32], + params_hash: vec![8; 32], + merkle_root: vec![9; 32], + }; + let bytes = ComputeJournal::new(&domain(), &result).unwrap().abi_bytes(); + + assert_eq!(bytes.len(), JOURNAL_BYTES); + assert_eq!(&bytes[..24], &[0; 24]); + assert_eq!(bytes[31], 1); + assert_eq!(&bytes[32..44], &[0; 12]); + assert_eq!(&bytes[44..64], &[2; 20]); + for (index, field) in bytes[64..].chunks_exact(32).enumerate() { + assert_eq!(field, &[index as u8 + 3; 32]); + } + + let short = ComputeResult { + merkle_root: vec![9; 31], + ..result + }; + assert!(ComputeJournal::new(&domain(), &short).is_err()); + } + + #[test] + fn the_header_round_trips_and_refuses_trailing_bytes() { + let header = GuestHeader { + domain: domain(), + params: vec![1, 2, 3], + indices: vec![10, 11], + published: vec![ + PublishedData { + commitment: Some([7; 32]), + metadata: vec![1; 25], + }, + PublishedData::default(), + ], + }; + let mut bytes = header.encode().unwrap(); + let decoded = GuestHeader::decode(&bytes).unwrap(); + assert_eq!(decoded.domain, header.domain); + assert_eq!(decoded.indices, header.indices); + assert_eq!(decoded.published.len(), 2); + + bytes.push(0); + assert!(GuestHeader::decode(&bytes).is_err()); + } + + /// The worker reads this format; `interfold-openvm-prover` pins the same bytes. + #[test] + fn the_item_format_is_pinned() { + let mut file = Vec::new(); + write_items(&mut file, [&[1u8, 2, 3][..], &[][..]].into_iter()).unwrap(); + assert_eq!( + file, + [2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0] + ); + } + + #[test] + fn items_round_trip_one_at_a_time() { + let items: Vec> = vec![vec![1, 2, 3], Vec::new(), vec![9; 1000]]; + let mut file = Vec::new(); + write_items(&mut file, items.iter().map(Vec::as_slice)).unwrap(); + + let mut reader = ItemReader::new(file.as_slice()).unwrap(); + assert_eq!(reader.remaining(), 3); + for item in &items { + assert_eq!(reader.next_item().unwrap().as_ref(), Some(item)); + } + assert_eq!(reader.next_item().unwrap(), None); + } + + #[test] + fn a_truncated_or_padded_file_is_refused() { + let mut file = Vec::new(); + write_items(&mut file, [&[1u8, 2, 3][..]].into_iter()).unwrap(); + + let mut truncated = ItemReader::new(&file[..file.len() - 1]).unwrap(); + assert!(truncated.next_item().is_err()); + + let mut padded_file = file.clone(); + padded_file.push(0); + let mut padded = ItemReader::new(padded_file.as_slice()).unwrap(); + padded.next_item().unwrap(); + assert!(padded.next_item().is_err()); + + let mut oversized = 1u32.to_le_bytes().to_vec(); + oversized.extend_from_slice(&(MAX_ITEM_BYTES as u64 + 1).to_le_bytes()); + assert!(ItemReader::new(oversized.as_slice()) + .unwrap() + .next_item() + .is_err()); + } +} diff --git a/crates/program-server/src/lib.rs b/crates/program-server/src/lib.rs index 51df53e62e..d7055a0f03 100644 --- a/crates/program-server/src/lib.rs +++ b/crates/program-server/src/lib.rs @@ -87,6 +87,10 @@ pub struct ComputeJob { pub domain: ComputeDomain, } +/// The default request body limit. Enough for development rounds; a service proving secure-parameter +/// rounds raises it with [`E3ProgramServerBuilder::with_max_request_bytes`]. +const DEFAULT_MAX_REQUEST_BYTES: usize = 10 * 1024 * 1024; + #[derive(Clone)] pub struct E3ProgramServerBuilder { runner: Arc, @@ -94,6 +98,7 @@ pub struct E3ProgramServerBuilder { host: Option, localhost_rewrite: Option, max_concurrent_jobs: usize, + max_request_bytes: usize, } impl E3ProgramServerBuilder { @@ -109,6 +114,7 @@ impl E3ProgramServerBuilder { host: None, localhost_rewrite: None, max_concurrent_jobs: 1, + max_request_bytes: DEFAULT_MAX_REQUEST_BYTES, } } @@ -136,12 +142,23 @@ impl E3ProgramServerBuilder { self } + /// Bound the size of a `/run_compute` request body (default 10 MiB). The ciphertexts arrive + /// hex-encoded, so a round needs about twice its binary size. + pub fn with_max_request_bytes(mut self, max_request_bytes: usize) -> Self { + self.max_request_bytes = max_request_bytes; + self + } + /// Build the E3ProgramServer pub fn build(self) -> Result { anyhow::ensure!( self.max_concurrent_jobs > 0, "max concurrent jobs must be greater than zero" ); + anyhow::ensure!( + self.max_request_bytes > 0, + "the request size limit must be greater than zero" + ); let webhook_client = reqwest::Client::builder() .connect_timeout(Duration::from_secs(5)) .timeout(Duration::from_secs(30)) @@ -155,6 +172,7 @@ impl E3ProgramServerBuilder { localhost_rewrite: self.localhost_rewrite, webhook_client, jobs: Arc::new(Semaphore::new(self.max_concurrent_jobs)), + max_request_bytes: self.max_request_bytes, }) } } @@ -167,6 +185,7 @@ pub struct E3ProgramServer { localhost_rewrite: Option, webhook_client: reqwest::Client, jobs: Arc, + max_request_bytes: usize, } impl E3ProgramServer { @@ -202,11 +221,11 @@ impl E3ProgramServer { localhost_rewrite: self.localhost_rewrite.clone(), webhook_client: self.webhook_client.clone(), jobs: Arc::clone(&self.jobs), + max_request_bytes: self.max_request_bytes, }; let server = HttpServer::new(move || { App::new() .app_data(web::Data::new(config.clone())) - .app_data(web::JsonConfig::default().limit(10 * 1024 * 1024)) // 10MB for prod params .wrap(Logger::default()) .route("/run_compute", web::post().to(handle_compute)) .route("/health", web::get().to(handle_health_check)) @@ -225,6 +244,7 @@ pub struct AppConfig { pub localhost_rewrite: Option, webhook_client: reqwest::Client, jobs: Arc, + max_request_bytes: usize, } /// Whether callbacks to addresses only reachable from inside the deployment are permitted. @@ -391,25 +411,50 @@ async fn call_webhook( } } - let response = client - .post(callback_url.clone()) - .json(&payload) - .send() - .await?; - - println!("Webhook response status: {}", response.status()); - if !response.status().is_success() { - return Err(anyhow::anyhow!( - "Webhook failed with status {}", - response.status() - )); + // A proof can take hours, so one dropped connection must not lose its result. Server errors, + // timeouts and rate limits are retried with backoff; any other refusal is final. + let mut last_error = None; + for attempt in 1_u32..=WEBHOOK_ATTEMPTS { + match client + .post(callback_url.clone()) + .json(&payload) + .send() + .await + { + Ok(response) if response.status().is_success() => { + println!("Webhook response status: {}", response.status()); + println!("✓ Webhook called successfully for E3 {}", e3_id); + return Ok(()); + } + Ok(response) => { + let status = response.status(); + let error = anyhow::anyhow!("Webhook failed with status {status}"); + if !(status.is_server_error() + || status == reqwest::StatusCode::REQUEST_TIMEOUT + || status == reqwest::StatusCode::TOO_MANY_REQUESTS) + { + return Err(error); + } + last_error = Some(error); + } + Err(error) => last_error = Some(error.into()), + } + if attempt < WEBHOOK_ATTEMPTS { + let delay = Duration::from_secs(1 << (attempt - 1)); + println!( + "Webhook attempt {attempt} failed; retrying in {} seconds", + delay.as_secs() + ); + tokio::time::sleep(delay).await; + } } - response.error_for_status()?; - println!("✓ Webhook called successfully for E3 {}", e3_id); - Ok(()) + Err(last_error.unwrap_or_else(|| anyhow::anyhow!("webhook delivery failed"))) } +/// How many times a callback is attempted before the result is given up. +const WEBHOOK_ATTEMPTS: u32 = 5; + async fn handle_webhook_delivery( client: &reqwest::Client, callback_url: &reqwest::Url, @@ -472,9 +517,23 @@ async fn process_computation_background( async fn handle_compute( config: web::Data, - req: web::Json, + body: web::Payload, ) -> ActixResult { println!("Processing computation..."); + // Admission first. A request body can be hundreds of megabytes, and buffering it only to + // refuse it would let a caller exhaust memory while a computation runs. The permit is released + // when this handler returns early. + let permit = Arc::clone(&config.jobs) + .try_acquire_owned() + .map_err(|_| actix_web::error::ErrorTooManyRequests("compute capacity exhausted"))?; + let body = body + .to_bytes_limited(config.max_request_bytes) + .await + .map_err(actix_web::error::ErrorPayloadTooLarge)??; + let mut req: ComputeRequest = serde_json::from_slice(&body) + .map_err(|e| actix_web::error::ErrorBadRequest(format!("invalid request: {e}")))?; + drop(body); + let e3_id = req .e3_id .clone() @@ -558,8 +617,8 @@ async fn handle_compute( } let fhe_inputs = FHEInputs { - params: req.params.clone(), - ciphertexts: req.ciphertext_inputs.clone(), + params: std::mem::take(&mut req.params), + ciphertexts: std::mem::take(&mut req.ciphertext_inputs), }; let domain = ComputeDomain::new( req.chain_id, @@ -577,9 +636,6 @@ async fn handle_compute( let callback_url = validated_callback_url(&callback_url, config.localhost_rewrite.as_deref()) .map_err(actix_web::error::ErrorBadRequest)?; - let permit = Arc::clone(&config.jobs) - .try_acquire_owned() - .map_err(|_| actix_web::error::ErrorTooManyRequests("compute capacity exhausted"))?; let runner = config.runner.clone(); let webhook_client = config.webhook_client.clone(); let background_e3_id = e3_id.clone(); diff --git a/crates/support-scripts/openvm/compile b/crates/support-scripts/openvm/compile new file mode 100755 index 0000000000..a5ecbab413 --- /dev/null +++ b/crates/support-scripts/openvm/compile @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-3.0-only +# +# Builds what `interfold program start` needs to prove this project's E3 program with OpenVM: +# +# 1. the guest in ./guest, transpiled to an OpenVM executable; +# 2. its application proving key, then the aggregation key and receipt identity (`prepare`); +# 3. the worker configuration, .interfold/caches/openvm/prover.json; +# 4. the proving service. +# +# Step 2 runs only when the executable or ./guest/openvm.toml changed since the last run. +# +# Environment, set by `interfold program compile` from `program.openvm`: +# OPENVM_PROVER_BIN the CPU worker +# OPENVM_PROVER_BIN_CUDA the CUDA worker; runs `prepare` when there is no CPU worker +# OPENVM_SETUP_DIR what `cargo openvm setup` wrote (default ~/.openvm) +# OPENVM_SEGMENT_MEMORY_BYTES the proving segment memory limit (default 8 GiB, fits a 16 GB GPU) +# CARGO_OPENVM the cargo-openvm command (default `cargo openvm`) +# OPENVM_BUILD_LOCKED=1 build the guest with --locked +set -euo pipefail + +PROJECT="$(pwd)" +GUEST="$PROJECT/guest" +OUT="$PROJECT/.interfold/caches/openvm" +SETUP="${OPENVM_SETUP_DIR:-$HOME/.openvm}" +WORKER="${OPENVM_PROVER_BIN:-${OPENVM_PROVER_BIN_CUDA:-}}" +read -r -a CARGO_OPENVM <<< "${CARGO_OPENVM:-cargo openvm}" + +if [ ! -f "$GUEST/Cargo.toml" ]; then + echo "No OpenVM guest at $GUEST" >&2 + exit 1 +fi +if [ -z "$WORKER" ]; then + echo "Set program.openvm.prover_bin or program.openvm.prover_bin_cuda to the OpenVM worker" >&2 + exit 1 +fi + +sha256() { + if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1"; else shasum -a 256 "$1"; fi | cut -d' ' -f1 +} + +mkdir -p "$OUT" + +echo "Building the OpenVM guest" +locked=() +if [ "${OPENVM_BUILD_LOCKED:-0}" = 1 ]; then locked=(--locked); fi +RUSTFLAGS="${RUSTFLAGS:-} --cfg crisp_openvm --cfg crisp_fhe_optimized" \ + "${CARGO_OPENVM[@]}" build --manifest-path "$GUEST/Cargo.toml" --target-dir "$OUT/guest-target" \ + --output-dir "$OUT/guest" ${locked[@]+"${locked[@]}"} + +EXE="$OUT/guest/e3-openvm-guest.vmexe" +KEYS="$OUT/keys" +PREPARED="$OUT/prepared" +INPUTS="$(sha256 "$EXE") $(sha256 "$GUEST/openvm.toml")" + +if [ "$(cat "$PREPARED/inputs" 2>/dev/null || true)" != "$INPUTS" ]; then + echo "Generating the application proving key" + "${CARGO_OPENVM[@]}" keygen --manifest-path "$GUEST/Cargo.toml" --target-dir "$OUT/guest-target" \ + --app-only --output-dir "$KEYS" + echo "Generating the aggregation key and the receipt identity" + rm -rf "$PREPARED" + "$WORKER" prepare "$KEYS/app.pk" "$EXE" "$PREPARED" + echo "$INPUTS" > "$PREPARED/inputs" +fi + +"$WORKER" write-config "$OUT/prover.json" "$KEYS/app.pk" "$EXE" "$PREPARED" "$SETUP" \ + "${OPENVM_SEGMENT_MEMORY_BYTES:-8589934592}" +echo "Receipt identity: $PREPARED/identity.json" + +echo "Building the OpenVM proving service" +cargo build --locked --release --bin e3-support-scripts-openvm diff --git a/crates/support-scripts/openvm/service/Cargo.toml b/crates/support-scripts/openvm/service/Cargo.toml new file mode 100644 index 0000000000..30dde22dcc --- /dev/null +++ b/crates/support-scripts/openvm/service/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "e3-support-scripts-openvm" +version = "0.1.0" +edition = "2024" + +[[bin]] +name = "e3-support-scripts-openvm" +path = "src/main.rs" + +[dependencies] +e3-openvm-host = { workspace = true } +e3-program-server = { workspace = true } +tokio = { version = "1.38", features = ["full"] } +anyhow = "1.0.86" +e3-user-program = { path = "../../../../program" } diff --git a/crates/support-scripts/openvm/service/src/main.rs b/crates/support-scripts/openvm/service/src/main.rs new file mode 100644 index 0000000000..512962dd1c --- /dev/null +++ b/crates/support-scripts/openvm/service/src/main.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! The OpenVM proving service for this project's E3 program. +//! +//! Serves the same `POST /run_compute` as the development runner, and answers with a real OpenVM +//! receipt. The worker, its configuration and the deadlines come from the environment that +//! `interfold program start` sets; see `e3_openvm_host::WorkerConfig`. + +use anyhow::{Context, Result}; +use e3_openvm_host::{ComputeDomain, Prover, WorkerConfig}; +use e3_program_server::E3ProgramServer; +use std::sync::Arc; + +fn env_or(name: &str, default: T) -> Result { + match std::env::var(name) { + Ok(value) if !value.is_empty() => value + .parse() + .map_err(|_| anyhow::anyhow!("{name} has an invalid value")), + _ => Ok(default), + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let prover = Arc::new(Prover::start(WorkerConfig::from_env()?).await?); + + let bind = env_or("OPENVM_BIND_ADDR", "127.0.0.1:13151".to_string())?; + let (host, port) = bind + .rsplit_once(':') + .context("OPENVM_BIND_ADDR must be host:port")?; + let port: u16 = port + .parse() + .context("OPENVM_BIND_ADDR has an invalid port")?; + + let server = E3ProgramServer::builder(move |job| { + let prover = Arc::clone(&prover); + async move { + let domain = ComputeDomain { + chain_id: job.domain.chain_id, + verifying_contract: job.domain.verifying_contract, + e3_id: job.domain.e3_id, + encryption_scheme_id: job.domain.encryption_scheme_id, + committee_public_key_hash: job.domain.committee_public_key_hash, + }; + prover + .prove( + job.inputs, + job.published, + domain, + e3_user_program::fhe_processor, + e3_user_program::policy(), + ) + .await + } + }) + .with_host(host) + .with_port(port) + .with_max_concurrent_jobs(env_or("MAX_CONCURRENT_COMPUTATIONS", 1)?) + .with_max_request_bytes(env_or("OPENVM_MAX_REQUEST_BYTES", 128 * 1024 * 1024)?) + .build()?; + + server.run().await +} diff --git a/crates/support-scripts/openvm/start b/crates/support-scripts/openvm/start new file mode 100755 index 0000000000..7055775177 --- /dev/null +++ b/crates/support-scripts/openvm/start @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-3.0-only +# +# Starts the OpenVM proving service. `interfold program start` sets the worker paths and the backend +# from `program.openvm`; the worker configuration defaults to the one `compile` wrote. +set -euo pipefail + +export OPENVM_PROVER_CONFIG="${OPENVM_PROVER_CONFIG:-$(pwd)/.interfold/caches/openvm/prover.json}" +exec cargo run --locked --release --bin e3-support-scripts-openvm diff --git a/crates/support-scripts/src/program_openvm.rs b/crates/support-scripts/src/program_openvm.rs index e30e3ff87a..50710e763d 100644 --- a/crates/support-scripts/src/program_openvm.rs +++ b/crates/support-scripts/src/program_openvm.rs @@ -4,48 +4,64 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -use crate::{traits::ProgramSupportApi, utils::run_bash_script_with_env}; +use crate::{ + traits::ProgramSupportApi, + utils::{ensure_script_exists, run_bash_script_with_env}, +}; use anyhow::{ensure, Context, Result}; use async_trait::async_trait; use e3_config::ProgramConfig; +use std::env; +/// Proves the project's E3 program with OpenVM, through the project's +/// `.interfold/support/openvm` scripts. pub struct ProgramSupportOpenVm(pub ProgramConfig); impl ProgramSupportOpenVm { - async fn run(&self, action: &str) -> Result<()> { + async fn run(&self, script: &str) -> Result<()> { let config = self.0.openvm().context( - "Set program.openvm with the repository, prover_bin, and prover_config paths", + "Set program.openvm.prover_bin to the CPU worker, program.openvm.prover_bin_cuda to \ + the CUDA worker, or both", )?; ensure!( - config.repository.is_absolute(), - "program.openvm.repository must be an absolute path" + config.prover_bin.is_some() || config.prover_bin_cuda.is_some(), + "Set program.openvm.prover_bin to the CPU worker, program.openvm.prover_bin_cuda to \ + the CUDA worker, or both" ); - let script = config.repository.join("scripts/run-openvm.sh"); - ensure!( - script.is_file(), - "The OpenVM build script is missing from the configured repository" - ); - let environment = vec![ - ( - "OPENVM_PROVER_BIN".to_owned(), - config.prover_bin.to_string_lossy().into_owned(), - ), - ( - "OPENVM_PROVER_CONFIG".to_owned(), - config.prover_config.to_string_lossy().into_owned(), - ), - ]; - run_bash_script_with_env(&config.repository, &script, &[action], &environment).await?; - Ok(()) + + let mut environment = vec![( + "OPENVM_BACKEND".to_owned(), + config.backend.as_str().to_owned(), + )]; + for (name, path) in [ + ("OPENVM_PROVER_BIN", &config.prover_bin), + ("OPENVM_PROVER_BIN_CUDA", &config.prover_bin_cuda), + ("OPENVM_PROVER_CONFIG", &config.prover_config), + ("OPENVM_SETUP_DIR", &config.setup_dir), + ] { + if let Some(path) = path { + ensure!( + path.is_absolute(), + "program.openvm paths must be absolute: {}", + path.display() + ); + environment.push((name.to_owned(), path.to_string_lossy().into_owned())); + } + } + + let cwd = env::current_dir()?; + let script = cwd.join(".interfold/support/openvm").join(script); + ensure_script_exists(&script).await?; + run_bash_script_with_env(&cwd, &script, &[], &environment).await } } #[async_trait] impl ProgramSupportApi for ProgramSupportOpenVm { async fn compile(&self) -> Result<()> { - self.run("service-build").await + self.run("compile").await } async fn start(&self) -> Result<()> { - self.run("service-start").await + self.run("start").await } } diff --git a/crates/support/Cargo.toml b/crates/support/Cargo.toml deleted file mode 100644 index d9f0bc92e3..0000000000 --- a/crates/support/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[workspace] -resolver = "3" -members = ["app", "host", "types", "program"] -exclude = ["openvm/guest", "openvm/prover"] - -[workspace.package] -version = "0.1.0" -edition = "2021" -rust-version = "1.91.1" - -[workspace.dependencies] -e3-support-app = { path = "./app" } -e3-support-host = { path = "./host" } -e3-user-program = { path = "./program" } -e3-support-types = { path = "./types" } -e3-fhe-params = { path = "../fhe-params" } - -alloy-primitives = { version = "1.3", default-features = false, features = [ - "rlp", - "serde", - "std", -]} -alloy-sol-types = { version = "1.3" } -alloy-signer-local = { version = "1.0" } -anyhow = { version = "=1.0.98" } -actix-web = "=4.11.0" -bincode = { version = "=1.3.3" } -bytemuck = { version = "=1.25.0" } -env_logger = "=0.11.8" -hex = { version = "=0.4.3" } -log = { version = "=0.4.27" } -reqwest = { version = "=0.12.22", features = ["json"] } -serde = { version = "1.0", features = ["derive", "std"] } -serde_json = "=1.0.145" -sha2 = "=0.10.9" -sha3 = "=0.10.8" -# Build this workspace from the repository root to include the guest source dependencies. -fhe = { package = "fhe", git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } -fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } -fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", rev = "873dc69c07eae251f88c4b5cacf6c4453e2c365a" } -e3-compute-provider = { path = "../compute-provider" } -tokio = { version = "=1.46.1", features = ["full"] } -rand = { version = "=0.9.2" } -tracing-subscriber = { version = "=0.3.20", features = ["env-filter"] } -url = { version = "=2.5.4" } -dotenvy = { version = "=0.15.7" } - -[profile.release] -debug = 1 -lto = true diff --git a/crates/support/Dockerfile b/crates/support/Dockerfile index 7100121dac..ab326c715d 100644 --- a/crates/support/Dockerfile +++ b/crates/support/Dockerfile @@ -4,11 +4,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential cmake pkg-config git libssl-dev ca-certificates protobuf-compiler \ && rm -rf /var/lib/apt/lists/* WORKDIR /app -# The support workspace uses repository-local guest dependencies. +# CRISP's OpenVM proving service. It is built in the CRISP workspace against the repository crates. COPY Cargo.toml Cargo.lock rust-toolchain.toml ./ COPY crates ./crates +COPY examples/CRISP/Cargo.toml examples/CRISP/Cargo.lock ./examples/CRISP/ +COPY examples/CRISP/.interfold/support ./examples/CRISP/.interfold/support COPY examples/CRISP/program ./examples/CRISP/program -RUN cargo build --locked --release --manifest-path crates/support/Cargo.toml -p e3-support-app -# Mount a separately built OpenVM worker, its configuration, and its proving artifacts. +COPY examples/CRISP/server ./examples/CRISP/server +COPY examples/CRISP/crates ./examples/CRISP/crates +RUN cd examples/CRISP && cargo build --locked --release --bin e3-support-scripts-openvm +# Mount the separately built OpenVM workers, their configuration, and the proving artifacts, and +# set OPENVM_PROVER_BIN, OPENVM_PROVER_BIN_CUDA, OPENVM_PROVER_CONFIG and OPENVM_BACKEND. ENV OPENVM_BIND_ADDR=0.0.0.0:13151 -CMD ["./crates/support/target/release/e3-support-app"] +CMD ["./examples/CRISP/target/release/e3-support-scripts-openvm"] diff --git a/crates/support/README.md b/crates/support/README.md deleted file mode 100644 index 014c89bbcd..0000000000 --- a/crates/support/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# OpenVM compute service - -The support service runs the Secure Process and returns a verified OpenVM receipt. It runs on the -operator's machine. It does not require a proving-market account, payment wallet, or program upload. - -The normal path is: - -`CRISP server → POST /run_compute → OpenVM worker → HTTP callback → ciphertext publication` - -The program server does not submit the publication transaction. CRISP verifies the callback, -publishes the ciphertext to its data-availability layer, and submits the resulting reference. -Both the protocol verifier and the application verifier must accept the compute proof. - -## Components - -- `app/`: the HTTP service, request admission, computation scheduling, and callback delivery. -- `host/`: native computation, worker execution, journal comparison, and proof-envelope encoding. -- `types/`: requests, callbacks, proof domains, guest inputs, and the nine-word journal. -- `program/`: the canonical CRISP processor and input policy, shared with the native host. -- `openvm/guest/`: the guest that proves the computation and reveals the journal digest. -- `openvm/prover/`: the separate worker that generates and verifies the EVM proof. - -These are isolated Cargo workspaces. Use the root `pnpm openvm` commands to select them. - -## Configure and start - -Follow [the OpenVM build instructions](openvm/README.md) to prepare the worker, guest, proving -keys, verifier artifact, and worker configuration. - -Set these deployment-local absolute paths in `interfold.config.yaml`: - -```yaml -program: - dev: false - openvm: - repository: ${OPENVM_REPOSITORY} - prover_bin: ${OPENVM_PROVER_BIN} - prover_config: ${OPENVM_PROVER_CONFIG} -``` - -Then run: - -```sh -interfold program compile -interfold program start -``` - -`compile` builds the native HTTP service. It does not regenerate the guest or proving keys. -`start` validates the configured worker and artifacts before it accepts requests. Missing -configuration is an error. There is no automatic unproved fallback. - -The CRISP reference guest uses CRISP's input policy. Another E3 program needs a host and guest -built against its own processor and policy. The contract, host, and guest must derive the same -input leaves, selected inputs, parameter hash, and journal. - -## HTTP interface - -The listener defaults to `127.0.0.1:13151`. Set `OPENVM_BIND_ADDR` to change it. - -- `GET /health` and `HEAD /health` report service health. -- `POST /run_compute` accepts the existing program-server request. It contains the full E3 domain, - BFV parameters, indexed ciphertexts, published commitments and metadata, and a callback URL. -- The immediate response acknowledges processing. It is not a proof or a publication receipt. - -A successful callback contains `status: "completed"`, `e3_id`, `ciphertext`, -`ciphertext_commitment`, and `proof`. Binary fields use hexadecimal encoding. -A failed callback contains `status: "failed"`, `e3_id`, and `error`. - -The proof envelope contains the seal, parameter hash, and input root. The seal contains the -Halo2 proof and all nine journal words. See [the receipt format](openvm/README.md#contract-migration). - -The service admits one active computation by default. Jobs are in memory. A service restart can lose an -accepted job. Operators must reconcile interrupted jobs and failed callback delivery. -Use authenticated admission control and a deployment-specific callback policy. Do not expose -the unrestricted listener to the Internet. - -## Container - -From the repository root: - -```sh -bash crates/support/scripts/build.sh -``` - -The container builds the native service, not the GPU worker. Mount the worker, its runtime -libraries, its configuration, and its proving artifacts. Provide GPU access for a CUDA worker. -Keep the service and worker on a compatible operating system. The CLI runs the configured local -service directly and does not pull a container image. - -## Verification - -```sh -pnpm openvm service-test -pnpm openvm contract-test -``` - -Use `pnpm openvm proof-test` for an externally supplied real proof. -Use `pnpm openvm service-e2e` for the live HTTP workflow on an isolated local chain. -[The OpenVM instructions](openvm/README.md#checks) list the required inputs and test boundaries. - -An explicit `program.dev: true` selects an unproved development runner. That runner is not -OpenVM and cannot pass a real receipt verifier. diff --git a/crates/support/app/Cargo.toml b/crates/support/app/Cargo.toml deleted file mode 100644 index c1312abd97..0000000000 --- a/crates/support/app/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "e3-support-app" -version = "0.1.0" -edition.workspace = true - -[dependencies] -actix-web.workspace = true -env_logger.workspace = true -serde.workspace = true -serde_json.workspace = true -tokio.workspace = true -e3-compute-provider.workspace = true -e3-support-types.workspace = true -reqwest.workspace = true -anyhow.workspace = true -hex.workspace = true - -[dependencies.e3-support-host] -workspace = true diff --git a/crates/support/app/src/main.rs b/crates/support/app/src/main.rs deleted file mode 100644 index 7137451ca1..0000000000 --- a/crates/support/app/src/main.rs +++ /dev/null @@ -1,436 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use actix_web::{middleware::Logger, web, App, HttpResponse, HttpServer, Result as ActixResult}; -use e3_compute_provider::FHEInputs; -use e3_compute_provider::PublishedData; -use e3_support_types::{ComputeDomain, ComputeRequest, WebhookPayload}; -use serde::Serialize; -use std::sync::{Arc, OnceLock}; -use std::time::Duration; -use tokio::sync::{OwnedSemaphorePermit, Semaphore}; - -#[derive(Serialize, Debug)] -struct ProcessingResponse { - status: String, - e3_id: String, -} - -async fn call_webhook(callback_url: &str, payload: &WebhookPayload) -> anyhow::Result<()> { - let (e3_id, status_label, ciphertext_len, commitment_len, proof_len) = match payload { - WebhookPayload::Completed { - e3_id, - ciphertext, - ciphertext_commitment, - proof, - } => ( - e3_id, - "completed", - ciphertext.len(), - ciphertext_commitment.len(), - proof.len(), - ), - WebhookPayload::Failed { e3_id, error } => { - println!("call_webhook() - status: failed, error: {}", error); - (e3_id, "failed", 0, 0, 0) - } - }; - - println!( - "call_webhook() - status: {}, ciphertext len: {}, commitment len: {}, proof len: {}", - status_label, ciphertext_len, commitment_len, proof_len - ); - - println!("Sending webhook to: {}", callback_url); - - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(30)) - .build()?; - let mut last_error = None; - - for attempt in 1_u32..=5 { - match client.post(callback_url).json(payload).send().await { - Ok(response) if response.status().is_success() => { - println!("Webhook response status: {}", response.status()); - println!("✓ Webhook called successfully for E3 {}", e3_id); - return Ok(()); - } - Ok(response) => { - let status = response.status(); - let retryable = status.is_server_error() - || status == reqwest::StatusCode::REQUEST_TIMEOUT - || status == reqwest::StatusCode::TOO_MANY_REQUESTS; - let error_body = response - .text() - .await - .unwrap_or_else(|error| format!("could not read response body: {error}")); - let error = anyhow::anyhow!("webhook returned {status}: {error_body}"); - if !retryable { - return Err(error); - } - last_error = Some(error); - } - Err(error) => last_error = Some(error.into()), - } - - if attempt < 5 { - let delay = Duration::from_secs(1_u64 << (attempt - 1)); - println!( - "Webhook attempt {attempt} failed; retrying in {} seconds", - delay.as_secs() - ); - tokio::time::sleep(delay).await; - } - } - - Err(last_error.unwrap_or_else(|| anyhow::anyhow!("webhook delivery failed"))) -} - -async fn run_computation_async( - fhe_inputs: FHEInputs, - domain: ComputeDomain, - published: Vec, -) -> anyhow::Result<(Vec, Vec, Vec)> { - println!("running computation..."); - let result = tokio::task::spawn_blocking(move || { - e3_support_host::run_compute(fhe_inputs, domain, published) - }) - .await?; - - let (output, ciphertext) = result?; - let proof = e3_support_host::encode_compute_proof(&output.seal, &output.result)?; - Ok((proof, ciphertext, output.result.ciphertext_commitment)) -} - -async fn process_computation_background( - e3_id: String, - callback_url: &str, - fhe_inputs: FHEInputs, - domain: ComputeDomain, - published: Vec, - // Held for the whole computation and dropped with it, which is what frees the slot. Taking it - // by value rather than borrowing is deliberate: the task is detached, so nothing else is alive - // to own it. - _permit: OwnedSemaphorePermit, -) -> anyhow::Result<()> { - match run_computation_async(fhe_inputs, domain, published).await { - Ok((proof, ciphertext, ciphertext_commitment)) => { - println!("computation finished!"); - println!("handling webhook delivery..."); - let payload = WebhookPayload::Completed { - e3_id: e3_id.clone(), - ciphertext, - ciphertext_commitment, - proof, - }; - call_webhook(callback_url, &payload).await?; - println!("Computation completed for E3 {}", e3_id); - Ok(()) - } - Err(e) => { - let error_msg = e.to_string(); - eprintln!("Computation failed for E3 {}: {}", e3_id, error_msg); - - let payload = WebhookPayload::Failed { - e3_id: e3_id.clone(), - error: format!("Compute failed: {}", error_msg), - }; - call_webhook(callback_url, &payload).await?; - - Err(e) - } - } -} - -/// Whether callbacks to addresses only reachable from inside the deployment are permitted. -/// -/// Off by default for private networks and internal hostnames. Loopback callbacks are permitted -/// separately so an isolated local CRISP server can receive results. -fn allow_private_callbacks() -> bool { - matches!( - std::env::var("ALLOW_PRIVATE_CALLBACKS") - .unwrap_or_default() - .as_str(), - "1" | "true" | "TRUE" | "yes" | "YES" - ) -} - -/// Validates a caller-supplied callback URL before this server makes a request to it. -/// -/// Without this, `callback_url` is a server-side request forgery primitive: the caller chooses a -/// destination and this server dials it, which reaches cloud metadata (169.254.169.254), loopback, -/// and anything else inside the network the server sits in. -/// -/// Literal addresses are checked exhaustively. A hostname is checked by name only, so a name that -/// resolves to a private address still passes and DNS rebinding remains possible — closing that -/// needs resolution at connect time and a pinned socket. -fn validate_callback_url(raw: &str) -> ActixResult<()> { - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - - let url = reqwest::Url::parse(raw) - .map_err(|e| actix_web::error::ErrorBadRequest(format!("invalid callback_url: {e}")))?; - - if !matches!(url.scheme(), "http" | "https") { - return Err(actix_web::error::ErrorBadRequest( - "callback_url must use http or https", - )); - } - if !url.username().is_empty() || url.password().is_some() { - return Err(actix_web::error::ErrorBadRequest( - "callback_url must not contain credentials", - )); - } - - if allow_private_callbacks() { - return Ok(()); - } - - // Allow loopback callbacks for local deployments. Block private networks, cloud metadata, - // and internal hostnames unless the operator explicitly enables private callbacks. - fn v4_is_internal(ip: Ipv4Addr) -> bool { - if ip.is_loopback() { - return false; - } - ip.is_private() - || ip.is_link_local() - || ip.is_broadcast() - || ip.is_documentation() - || ip.is_unspecified() - || ip.octets()[0] == 0 - || (ip.octets()[0] == 100 && (64..128).contains(&ip.octets()[1])) - } - - fn v6_is_internal(ip: Ipv6Addr) -> bool { - if let Some(mapped) = ip.to_ipv4_mapped() { - return v4_is_internal(mapped); - } - if ip.is_loopback() { - return false; - } - ip.is_unspecified() - || (ip.segments()[0] & 0xfe00) == 0xfc00 - || (ip.segments()[0] & 0xffc0) == 0xfe80 - } - - let internal = match url.host_str() { - Some(host) => { - let bare = host.trim_start_matches('[').trim_end_matches(']'); - match bare.parse::() { - Ok(IpAddr::V4(ip)) => v4_is_internal(ip), - Ok(IpAddr::V6(ip)) => v6_is_internal(ip), - Err(_) => { - // `localhost` resolves to loopback, and is allowed for the same reason. - let lowered = bare.to_ascii_lowercase(); - lowered.ends_with(".local") || lowered.ends_with(".internal") - } - } - } - None => true, - }; - - if internal { - return Err(actix_web::error::ErrorBadRequest( - "callback_url must not point at a private or link-local address; \ - set ALLOW_PRIVATE_CALLBACKS=1 to permit it for local development", - )); - } - - Ok(()) -} - -/// How many computations may be in flight at once. -/// -/// Proving is the most expensive thing this process does, and the handler previously spawned one -/// detached task per request with nothing bounding them: a caller could open as many as they liked -/// and exhaust CPU, memory, and GPU workers together. One at a time by -/// default, because a single proof already saturates the machine. -fn max_concurrent_computations() -> usize { - std::env::var("MAX_CONCURRENT_COMPUTATIONS") - .ok() - .and_then(|value| value.parse().ok()) - .filter(|value| *value > 0) - .unwrap_or(1) -} - -/// Permits for in-flight computations, sized once on first use. -static COMPUTE_SLOTS: OnceLock> = OnceLock::new(); - -fn compute_slots() -> &'static Arc { - COMPUTE_SLOTS.get_or_init(|| Arc::new(Semaphore::new(max_concurrent_computations()))) -} - -/// Width of the slot an E3 program packs into its published metadata, in bytes. -/// -/// Mirrors `abi.encodePacked(address, uint40)` — the convention the starter contract uses and the -/// one `crates/program-server` implements. Duplicated rather than shared because this workspace -/// builds standalone, outside the root workspace, so it cannot depend on that crate. -const SLOT_BYTES: usize = 20; -/// Width of the parent index in the same packing. -const PARENT_BYTES: usize = 5; -/// Largest parent index that fits `PARENT_BYTES`. -const MAX_PARENT: u64 = (1u64 << (8 * PARENT_BYTES as u64)) - 1; - -/// Rebuilds what the E3 program published alongside each ciphertext. -/// -/// Both widths are checked rather than coerced. This endpoint takes JSON from the network and the -/// packing is fixed-width: a slot of the wrong length shifts every byte after it, and a parent -/// above `uint40` would be truncated into a different, valid-looking index. Either produces -/// metadata the E3 program never published, and the only symptom is an input root the guest -/// derives and the contract rejects. -fn published_from(req: &ComputeRequest) -> ActixResult> { - if req.input_commitments.is_empty() - && req.input_slots.is_empty() - && req.input_parents.is_empty() - { - return Ok(Vec::new()); - } - - if req.input_commitments.len() != req.ciphertext_inputs.len() { - return Err(actix_web::error::ErrorBadRequest( - "input_commitments must have one entry per ciphertext input", - )); - } - if !req.input_slots.is_empty() && req.input_slots.len() != req.input_commitments.len() { - return Err(actix_web::error::ErrorBadRequest( - "input_slots must have one entry per ciphertext input", - )); - } - if req.input_slots.len() != req.input_parents.len() { - return Err(actix_web::error::ErrorBadRequest( - "input_slots and input_parents must have the same length", - )); - } - - req.input_commitments - .iter() - .enumerate() - .map(|(index, hex_commitment)| { - let bytes = hex::decode(hex_commitment.trim_start_matches("0x")) - .map_err(|e| actix_web::error::ErrorBadRequest(format!("bad commitment: {e}")))?; - let commitment: [u8; 32] = bytes.try_into().map_err(|_| { - actix_web::error::ErrorBadRequest("each commitment must be 32 bytes") - })?; - - let mut metadata = Vec::new(); - if let Some(hex_slot) = req.input_slots.get(index) { - let slot = hex::decode(hex_slot.trim_start_matches("0x")) - .map_err(|e| actix_web::error::ErrorBadRequest(format!("bad slot: {e}")))?; - if slot.len() != SLOT_BYTES { - return Err(actix_web::error::ErrorBadRequest(format!( - "each slot must be {SLOT_BYTES} bytes, got {}", - slot.len() - ))); - } - metadata.extend_from_slice(&slot); - - let parent = req.input_parents.get(index).copied().unwrap_or_default(); - if parent > MAX_PARENT { - return Err(actix_web::error::ErrorBadRequest(format!( - "each parent must fit in {PARENT_BYTES} bytes (at most {MAX_PARENT}), got {parent}" - ))); - } - metadata.extend_from_slice(&parent.to_be_bytes()[8 - PARENT_BYTES..]); - } - - Ok(PublishedData { - commitment: Some(commitment), - metadata, - }) - }) - .collect() -} - -async fn handle_compute(req: web::Json) -> ActixResult { - println!("Processing computation..."); - let e3_id = req - .e3_id - .clone() - .ok_or_else(|| actix_web::error::ErrorBadRequest("e3_id is required"))?; - let callback_url = req - .callback_url - .clone() - .ok_or_else(|| actix_web::error::ErrorBadRequest("callback_url is required"))?; - validate_callback_url(&callback_url)?; - - // Admission control. Refused up front with 429 rather than queued, so a caller learns - // immediately instead of holding a connection behind an unbounded backlog. - let permit = Arc::clone(compute_slots()) - .try_acquire_owned() - .map_err(|_| { - actix_web::error::ErrorTooManyRequests( - "a computation is already running; retry once it completes", - ) - })?; - let fhe_inputs = FHEInputs { - params: req.params.clone(), - ciphertexts: req.ciphertext_inputs.clone(), - }; - let published = published_from(&req)?; - let domain = ComputeDomain::new( - req.chain_id, - &req.interfold_address, - &e3_id, - &req.encryption_scheme_id, - &req.committee_public_key_hash, - ) - .map_err(actix_web::error::ErrorBadRequest)?; - - // Process computation in background - let background_e3_id = e3_id.clone(); - tokio::spawn(async move { - if let Err(e) = process_computation_background( - background_e3_id.clone(), - &callback_url, - fhe_inputs, - domain, - published, - permit, - ) - .await - { - eprintln!( - "✗ Background computation failed for E3 {}: {:?}", - background_e3_id, e - ); - } - }); - Ok(HttpResponse::Ok().json(ProcessingResponse { - status: "processing".to_string(), - e3_id, - })) -} - -async fn handle_health_check() -> ActixResult { - Ok(HttpResponse::Ok().json(ProcessingResponse { - status: "healthy".to_string(), - e3_id: "0".to_string(), - })) -} - -#[actix_web::main] -async fn main() -> anyhow::Result<()> { - env_logger::init(); - e3_support_host::check_configuration()?; - let bind_addr = std::env::var("OPENVM_BIND_ADDR").unwrap_or_else(|_| "127.0.0.1:13151".into()); - let request_limit: usize = std::env::var("OPENVM_MAX_REQUEST_BYTES") - .unwrap_or_else(|_| (128 * 1024 * 1024).to_string()) - .parse()?; - anyhow::ensure!( - request_limit > 0 && request_limit <= 1024 * 1024 * 1024, - "OPENVM_MAX_REQUEST_BYTES must be between 1 byte and 1 GiB" - ); - let server = HttpServer::new(move || { - App::new() - .app_data(web::JsonConfig::default().limit(request_limit)) - .wrap(Logger::default()) - .route("/run_compute", web::post().to(handle_compute)) - .route("/health", web::get().to(handle_health_check)) - .route("/health", web::head().to(handle_health_check)) - }) - .bind(&bind_addr)?; - println!("🚀 FHE Compute Service listening on http://{}", bind_addr); - server.run().await.map_err(Into::into) -} diff --git a/crates/support/host/Cargo.toml b/crates/support/host/Cargo.toml deleted file mode 100644 index ed4c0869cb..0000000000 --- a/crates/support/host/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "e3-support-host" -version = { workspace = true } -edition = { workspace = true } - -[dependencies] -bincode = { workspace = true } -serde = { workspace = true } -alloy-primitives = { workspace = true } -alloy-sol-types = { workspace = true } -anyhow = { workspace = true } -tokio = { workspace = true } -e3-compute-provider = { workspace = true } -e3-support-types = { workspace = true } -e3-user-program = { workspace = true } - -tempfile = "3" -sha2.workspace = true -serde_json.workspace = true -hex.workspace = true - -[dev-dependencies] -hex = { workspace = true } diff --git a/crates/support/host/README.md b/crates/support/host/README.md deleted file mode 100644 index dfbe2e9e96..0000000000 --- a/crates/support/host/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# OpenVM host - -The host runs the canonical processor and policy to derive the ciphertext and nine-word journal. It -passes the input and expected journal to a separate OpenVM worker. - -The worker must generate a real EVM proof, verify the application identity and journal, and write a -verified seal. The host returns the ciphertext, SAFE commitment, and compute-proof envelope to the -HTTP service. A worker error fails the job. - -See [the service instructions](../README.md) and -[the OpenVM build instructions](../openvm/README.md). diff --git a/crates/support/host/src/lib.rs b/crates/support/host/src/lib.rs deleted file mode 100644 index 0c4fd47d46..0000000000 --- a/crates/support/host/src/lib.rs +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -use alloy_primitives::{Bytes, B256}; -use alloy_sol_types::SolValue; -use anyhow::{ensure, Context, Result}; -use e3_compute_provider::{ComputeInput, FHEInputs, PublishedData}; -use e3_support_types::{ComputeDomain, ComputeGuestInput, ComputeJournal}; -use std::{env, fs, path::PathBuf, process::Command}; - -pub struct OpenVmOutput { - pub result: ComputeJournal, - pub seal: Vec, -} - -/// Reject missing prover configuration before the service accepts work. -pub fn check_configuration() -> Result<()> { - for name in ["OPENVM_PROVER_BIN", "OPENVM_PROVER_CONFIG"] { - let path = PathBuf::from(env::var(name).with_context(|| format!("Set {name}"))?); - ensure!( - path.is_absolute() && path.is_file(), - "{name} must name an existing absolute file path" - ); - } - let status = Command::new(env::var("OPENVM_PROVER_BIN")?) - .arg("check") - .arg(env::var("OPENVM_PROVER_CONFIG")?) - .status()?; - ensure!(status.success(), "OpenVM configuration validation failed"); - Ok(()) -} - -pub fn run_compute( - params: FHEInputs, - domain: ComputeDomain, - published: Vec, -) -> Result<(OpenVmOutput, Vec)> { - ensure!( - params.ciphertexts.len() <= 1024, - "The input count exceeds the guest limit" - ); - let input = ComputeGuestInput { - domain: domain.clone(), - input: ComputeInput { - fhe_inputs: params, - published, - }, - }; - let (result, ciphertext) = input - .input - .run(e3_user_program::fhe_processor, e3_user_program::policy()) - .map_err(|error| anyhow::anyhow!("{error}"))?; - let journal = ComputeJournal::new(domain, result).map_err(anyhow::Error::msg)?; - let journal_bytes = journal.abi_bytes().map_err(anyhow::Error::msg)?; - let input_bytes = bincode::serialize(&input)?; - ensure!( - input_bytes.len() <= 512 * 1024 * 1024 - 16, - "The input exceeds the guest byte limit" - ); - let job = tempfile::Builder::new() - .prefix("interfold-openvm-") - .tempdir()?; - let input_path = job.path().join("input.bin"); - let journal_path = job.path().join("journal.bin"); - let seal_path = job.path().join("seal.bin"); - fs::write(&input_path, input_bytes)?; - fs::write(&journal_path, journal_bytes)?; - let status = Command::new(env::var("OPENVM_PROVER_BIN").context("Set OPENVM_PROVER_BIN")?) - .arg("prove") - .arg(env::var("OPENVM_PROVER_CONFIG").context("Set OPENVM_PROVER_CONFIG")?) - .arg(&input_path) - .arg(&journal_path) - .arg(&seal_path) - .status() - .context("Cannot start the OpenVM prover")?; - ensure!( - status.success(), - "OpenVM proof generation or verification failed" - ); - let seal = fs::read(seal_path).context("The OpenVM prover did not return a verified seal")?; - ensure!(seal.len() == 2144, "The OpenVM seal has an invalid length"); - Ok(( - OpenVmOutput { - result: journal, - seal, - }, - ciphertext, - )) -} - -pub fn encode_compute_proof(seal: &[u8], result: &ComputeJournal) -> Result> { - result.abi_bytes().map_err(anyhow::Error::msg)?; - ensure!(seal.len() == 2144, "The OpenVM seal has an invalid length"); - Ok(( - Bytes::copy_from_slice(seal), - B256::from_slice(&result.params_hash), - B256::from_slice(&result.merkle_root), - ) - .abi_encode_params()) -} - -#[cfg(test)] -mod tests { - use super::*; - use e3_compute_provider::ComputeResult; - - #[test] - fn journal_and_envelope_preserve_all_fields() { - let domain = ComputeDomain { - chain_id: 1, - verifying_contract: [2; 20], - e3_id: [3; 32], - encryption_scheme_id: [4; 32], - committee_public_key_hash: [5; 32], - }; - let mut journal = ComputeJournal::new( - domain, - ComputeResult { - ciphertext_hash: vec![6; 32], - ciphertext_commitment: vec![7; 32], - params_hash: vec![8; 32], - merkle_root: vec![9; 32], - }, - ) - .unwrap(); - let bytes = journal.abi_bytes().unwrap(); - assert_eq!(bytes.len(), 288); - assert_eq!(&bytes[..24], &[0; 24]); - assert_eq!(&bytes[32..44], &[0; 12]); - for (i, field) in bytes[64..].chunks_exact(32).enumerate() { - assert_eq!(field, &[i as u8 + 3; 32]); - } - let envelope = encode_compute_proof(&vec![0; 2144], &journal).unwrap(); - assert_eq!(envelope.len(), 2272); - assert_eq!(&envelope[32..64], &[8; 32]); - assert_eq!(&envelope[64..96], &[9; 32]); - assert!(encode_compute_proof(&[], &journal).is_err()); - journal.e3_id.pop(); - assert!(encode_compute_proof(&vec![0; 2144], &journal).is_err()); - } - - #[test] - #[ignore = "Requires OPENVM_TEST_INPUT and OPENVM_TEST_JOURNAL"] - fn native_result_matches_external_guest_journal() -> Result<()> { - let input: ComputeGuestInput = - bincode::deserialize(&fs::read(env::var("OPENVM_TEST_INPUT")?)?)?; - let (result, _) = input - .input - .run(e3_user_program::fhe_processor, e3_user_program::policy()) - .map_err(|error| anyhow::anyhow!("{error}"))?; - let journal = ComputeJournal::new(input.domain, result).map_err(anyhow::Error::msg)?; - assert_eq!( - journal.abi_bytes().map_err(anyhow::Error::msg)?, - fs::read(env::var("OPENVM_TEST_JOURNAL")?)? - ); - Ok(()) - } -} diff --git a/crates/support/openvm/README.md b/crates/support/openvm/README.md deleted file mode 100644 index b1abaed75b..0000000000 --- a/crates/support/openvm/README.md +++ /dev/null @@ -1,166 +0,0 @@ -# CRISP OpenVM compute backend - -OpenVM replaces RISC Zero and Boundless in the support service and the CRISP deployment path. This -is a new guest and verifier deployment, not an upgrade of an existing receipt. Existing deployment -records and legacy RISC Zero contracts remain unchanged. This branch does not deploy contracts or -change a live network. - -## Build - -Use Rust 1.91.1 and the OpenVM CLI and guest toolchain for the pinned v2.0.2 SDK. Install the SDK -prerequisites before these commands. CUDA builds also require the CUDA toolkit, driver libraries, -and the correct GPU architecture in the build environment. - -From the repository root: - -```sh -pnpm openvm guest build -pnpm openvm guest keygen --app-only -pnpm openvm prover-build --features cuda -pnpm openvm service-build --release -``` - -Omit `--features cuda` for a CPU worker. The native HTTP service has no SDK or CUDA dependency. The -worker is a separate executable so a proof failure does not abort the service process. - -The guest uses fhe.rs at the revision that the workspace pins. That revision includes lazy BFV -multiplication tables and canonical power-basis decoding (gnosisguild/fhe.rs#210), so no local FHE -patch is needed. The optimized guest enables direct coefficient packing, canonical power-basis -decoding, lazy BFV products, modular Poseidon2, SHA-256, and Keccak. -The native service uses the same CRISP policy source and compares its journal with the proved -output. - -Use the built worker's `prepare ` command to generate -the full aggregation key and application identity. Do not use an aggregation key from another VM -configuration. `check` and `prove` derive the identity from the executable and keys and reject a -mismatch. - -Obtain the compatible Halo2 proving key, KZG parameters, and generated verifier artifact for the -pinned OpenVM release. Verify their provenance and checksums. Keep all generated artifacts under -`target/` or outside the repository. Never commit proving keys, proofs, inputs, benchmark reports, -operator accounts, or machine-specific configuration. - -## Worker configuration - -Create a private deployment-local JSON configuration with these fields. There are no deployment -identity or path defaults. - -| Field | Value | -| ---------------------- | ------------------------------------------------------------------------ | -| `app_pk` | Absolute path to the guest application proving key | -| `executable` | Absolute path to the guest VM executable | -| `aggregation_pk` | Absolute path to the full aggregation key from `prepare` | -| `halo2_pk` | Absolute path to the compatible Halo2 proving key | -| `halo2_params_dir` | Absolute path to the KZG parameter directory | -| `verifier_artifact` | Absolute path to the SDK-generated verifier bytecode JSON | -| `verifier_sha256` | SHA-256 digest of that JSON file, lowercase hexadecimal without a prefix | -| `app_commit` | The `app_commit` object from `prepare`'s identity JSON | -| `segment_memory_bytes` | Nonzero segment memory limit for the prover machine | - -Run `interfold-openvm-prover check ` before service startup. Configure -`OPENVM_PROVER_BIN` and `OPENVM_PROVER_CONFIG` with absolute file paths, then run -`pnpm openvm service-start`. For the Interfold CLI, set `program.openvm.repository`, -`program.openvm.prover_bin`, and `program.openvm.prover_config`; these are deployment-local paths. -Legacy `program.risc0` settings do not select a fallback backend. Explicit `program.dev` remains a -separate development runner and does not produce an OpenVM receipt. - -The service binds to `127.0.0.1:13151` by default. Set `OPENVM_BIND_ADDR` to change the listener. -The container binds to `0.0.0.0:13151`; restrict its published port and network access. The JSON -request limit is 128 MiB. Set `OPENVM_MAX_REQUEST_BYTES` to change it, up to 1 GiB. The guest's -binary input limit is separate and remains 512 MiB minus 16 bytes. - -The existing `POST /run_compute` and completed/failed callback formats remain unchanged. The worker -generates an application proof, recursive aggregate, and Halo2 EVM proof. It executes the configured -EVM verifier, checks both application commitments, and checks the expected journal before it writes -a seal. A failed proof sends a failed callback. There is no fake-proof mode. - -Jobs are in memory, with one active computation per service process by default. Set -`MAX_CONCURRENT_COMPUTATIONS` only when the machine can prove that many jobs concurrently. A restart -can lose an accepted job. Operators must reconcile jobs and retry failed callback delivery; this -change does not add a durable job queue. Run the service behind authenticated admission control. Set -callback access policy for the deployment; do not expose an unrestricted service to the Internet. - -## Contract migration - -The guest reveals SHA-256 of nine consecutive 32-byte ABI words: - -1. Chain ID -2. Interfold address -3. Full uint256 E3 ID -4. Encryption scheme ID -5. Committee public-key hash -6. Ciphertext output hash -7. SAFE ciphertext commitment -8. Parameter hash -9. Input root - -The seal is `abi.encode(uint8(1), bytes(halo2ProofData), bytes32[9](journalWords))`. The compute -envelope remains `abi.encode(bytes(seal), bytes32(paramsHash), bytes32(inputRoot))`. The journal is -288 bytes, not the legacy RISC Zero serialization. - -The CRISP deploy script requires `OPENVM_APP_EXE_COMMIT` and `OPENVM_APP_VM_COMMIT`, plus exactly -one Halo2 verifier source: - -- `OPENVM_VERIFIER_ARTIFACT` and `OPENVM_VERIFIER_SHA256`: check and deploy the bytecode JSON. -- `OPENVM_HALO2_VERIFIER` and `OPENVM_HALO2_RUNTIME_CODE_HASH`: check an existing deployment's code. - -It installs `OpenVmReceiptVerifier` and `OpenVmBfvCiphertextVerifier`. Missing configuration stops -deployment. Its mock mode applies only to other test components; it never creates a mock compute -receipt verifier. The template permits an explicitly unproved test only with -`TEMPLATE_UNPROVED_TEST=1` on chain ID 31337. - -The receipt identity binds the Halo2 verifier address, executable commitment, and VM commitment. -Both the protocol BFV verifier and CRISP application verifier must use that identity. Both -verification calls remain mandatory. CRISP independently checks its stored parameter hash and input -root. Existing rounds retain their request-time verifier snapshot and must drain before a live -migration. The historical RISC Zero mainnet activation scripts are not OpenVM migration scripts. Do -not use them to activate this backend. - -No gas override or proof-verification bypass is included. On-chain verifier optimization is separate -work. The compute path remains unaudited. - -## Checks - -```sh -pnpm openvm service-test -pnpm openvm contract-test -``` - -`pnpm openvm proof-test` requires externally supplied `OPENVM_TEST_IDENTITY`, `OPENVM_TEST_JOURNAL`, -`OPENVM_TEST_VERIFIER`, and `OPENVM_TEST_VERIFIER_SHA256`. Set `OPENVM_TEST_PROOF` to a proof JSON -file or `OPENVM_TEST_SEAL` to a binary seal from the worker. It verifies a real proof on an -in-memory chain and rejects changed journal words, application commitments, and proof data. It does -not submit a public transaction. No local proof fixture is part of this branch. - -### Live HTTP round - -`pnpm openvm service-e2e` exercises CRISP input submission and indexing, the running OpenVM service, -the HTTP callback, and automatic ciphertext publication. It requires an isolated loopback RPC with -chain ID 31337 and a running, configured program service. Use Anvil for long local rounds: the -pinned Hardhat node can expire live subscriptions after five minutes. - -Build the CRISP server with `pnpm openvm crisp-server-build --release`. Generate fresh test inputs -with `pnpm openvm fixture 100 `. The fixture uses the secure-8192 preset. The -generator keeps its secret key in memory and checks the native aggregate and plaintext before -writing the fixture. - -Set these test-only environment variables: - -| Variable | Meaning | -| ----------------------------- | ---------------------------------------------------------- | -| `LOCAL_RPC_URL` | Isolated loopback EVM RPC | -| `OPENVM_E2E_FIXTURE` | Directory generated by the fixture command | -| `OPENVM_E2E_SERVER` | Absolute path to the CRISP server binary | -| `OPENVM_E2E_OUTPUT` | New directory for the test report and logs | -| `OPENVM_E2E_PROGRAM_URL` | Running program service reachable from CRISP | -| `OPENVM_E2E_CALLBACK_URL` | CRISP URL reachable from the program service | -| `OPENVM_E2E_LOCAL_SERVER_URL` | Local CRISP listener; defaults to `http://127.0.0.1:14000` | -| `OPENVM_TEST_IDENTITY` | Prepared identity JSON matching the worker | -| `OPENVM_TEST_VERIFIER` | Halo2 verifier bytecode JSON matching the worker | -| `OPENVM_TEST_VERIFIER_SHA256` | Expected SHA-256 of that JSON | - -The test deploys real OpenVM receipt and protocol verifiers. It rejects a changed proof, checks the -indexed tally, and checks settlement. Randomness, DKG proofs, ballot proofs and census, data -availability, and threshold-decryption proofs are explicit local mocks. This is a real compute-proof -integration test, not proof of a fully cryptographic distributed E3 round. Reports, inputs, and -generated proofs stay in the supplied output directories and must not be committed. diff --git a/crates/support/openvm/guest/src/main.rs b/crates/support/openvm/guest/src/main.rs deleted file mode 100644 index 76a40b7eea..0000000000 --- a/crates/support/openvm/guest/src/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -openvm::init!(); - -use bincode::Options; -use e3_support_types::{ComputeGuestInput, ComputeJournal}; -use sha2::Digest; - -fn main() { - let bytes = openvm::io::read_vec(); - const MAX_BYTES: usize = 512 * 1024 * 1024 - 16; - assert!(bytes.len() <= MAX_BYTES, "The input exceeds the byte limit"); - let input: ComputeGuestInput = bincode::DefaultOptions::new() - .with_fixint_encoding() - .with_limit(MAX_BYTES as u64) - .reject_trailing_bytes() - .deserialize(&bytes) - .expect("Invalid compute input"); - assert!( - input.input.fhe_inputs.ciphertexts.len() <= 1024, - "Too many inputs" - ); - let (result, _) = input - .input - .run(e3_user_program::fhe_processor, e3_user_program::policy()) - .expect("Ciphertext aggregation failed"); - let journal = ComputeJournal::new(input.domain, result) - .expect("Invalid compute journal") - .abi_bytes() - .expect("Invalid journal encoding"); - let digest = openvm_sha2::Sha256::digest(&journal); - for (index, word) in digest.chunks_exact(4).enumerate() { - openvm::io::reveal_u32(u32::from_le_bytes(word.try_into().unwrap()), index); - } -} diff --git a/crates/support/program/Cargo.toml b/crates/support/program/Cargo.toml deleted file mode 100644 index 2ef42fba62..0000000000 --- a/crates/support/program/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "e3-user-program" -version = "0.1.0" -edition = "2024" - -[lib] -path = "../../../examples/CRISP/program/src/lib.rs" - -[features] -openvm-hashes = ["dep:openvm-sha2", "dep:openvm-keccak256", "e3-compute-provider/openvm-hashes"] - -[dependencies] -fhe = { workspace = true } -fhe-traits = { workspace = true } -e3-compute-provider = { workspace = true } -e3-fhe-params = { workspace = true, features = ["abi-encoding"] } -sha2 = { workspace = true } -sha3 = { workspace = true } - -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } -openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", optional = true } diff --git a/crates/support/program/src/lib.rs b/crates/support/program/src/lib.rs deleted file mode 100644 index b3c6f30258..0000000000 --- a/crates/support/program/src/lib.rs +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use e3_compute_provider::FHEProcessorInput; -use fhe::bfv::Ciphertext; -use fhe_traits::{DeserializeParametrized, Serialize}; - -/// The input policy this E3 program requires. -/// -/// Every E3 program exports one beside its processor, so the guest and the dev runner do not need -/// to know which program they are running. -pub fn policy() -> e3_compute_provider::InputPolicy { - policy::crisp() -} - -/// CRISP Implementation of the CiphertextProcessor function -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { - let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); - - sum += &ciphertext; - } - - sum.to_bytes() -} - -/// CRISP's answers to how an input becomes a leaf and which inputs are tallied. -/// -/// Both are specific to this program and its contract. They live here, beside the `CRISPProgram` -/// they must agree with, rather than in `e3-compute-provider`, which every E3 program shares. -pub mod policy { - use e3_compute_provider::policy::{leaf_from_digest, PublishedInput}; - use e3_compute_provider::{ComputeError, InputPolicy}; - use sha2::{Digest, Sha256}; - use sha3::Keccak256; - use std::collections::BTreeMap; - - /// The metadata `CRISPProgram` publishes with each input: 20-byte slot, then a 5-byte parent. - const METADATA_LEN: usize = 25; - - /// What `CRISPProgram` publishes alongside one ciphertext. - struct Metadata { - slot: [u8; 20], - /// The tree index of the entry this input extends, or `None` when it extends nothing. - parent: Option, - } - - /// Splits the published metadata, which is `slot || parentIndexPlusOne` as - /// `abi.encodePacked(address, uint40)` lays it out. - fn metadata_of(input: &PublishedInput) -> Result { - if input.metadata.len() != METADATA_LEN { - return Err(ComputeError::LeafCommitment { - index: input.index, - reason: format!( - "expected {METADATA_LEN} bytes of slot and parent, got {}", - input.metadata.len() - ), - }); - } - - let mut slot = [0u8; 20]; - slot.copy_from_slice(&input.metadata[..20]); - - let mut parent_plus_one: u64 = 0; - for byte in &input.metadata[20..] { - parent_plus_one = (parent_plus_one << 8) | u64::from(*byte); - } - - Ok(Metadata { - slot, - parent: parent_plus_one.checked_sub(1), - }) - } - - /// `sha256(keccak256(ciphertext) || commitment || slot || parent) mod SNARK_SCALAR_FIELD`. - /// - /// Must stay byte-identical to `CRISPProgram.inputLeaf`, or no root will ever match. It binds - /// four things: the bytes, because the Noir proof constrains only the commitment and never sees - /// the serialized ciphertext; the commitment, so no commitment can be paired with any - /// ciphertext; the slot, because selection is per slot and an unbound slot would let a prover - /// re-group entries; and the parent, because selection walks the slot's chain by it. - pub fn leaf(input: &PublishedInput) -> Result { - let commitment = input - .commitment - .ok_or_else(|| ComputeError::LeafCommitment { - index: input.index, - reason: "CRISP publishes a commitment with every input".to_string(), - })?; - // Hashed as published rather than as parsed, so the leaf cannot drift from the contract's - // `abi.encodePacked` layout. Parsed first only to refuse the wrong length. - metadata_of(input)?; - - let mut outer = Sha256::new(); - outer.update(Keccak256::digest(input.ciphertext)); - outer.update(commitment); - outer.update(input.metadata); - Ok(leaf_from_digest(&outer.finalize())) - } - - /// The end of each slot's chain of usable entries. - /// - /// CRISP's input tree is append-only: anyone may write to any census member's slot, since the - /// mask path checks no signature. Overwriting in place would let a third party replace the - /// bytes of a counted vote and erase it, so entries accumulate and one per slot is selected - /// here. - /// - /// Each entry names the entry it extends, and an entry is taken only when two things hold: - /// - /// - its bytes reproduce its commitment, so it is a ciphertext anyone can read; and - /// - the entry it names is the one currently selected for that slot. - /// - /// The first rule is what stops a submitter poisoning a slot with bytes that decode to nothing. - /// The second is what stops one reaching back past a vote: an entry built on a superseded - /// ciphertext would put that older ciphertext back in the slot, erasing the vote in between. - /// - /// Together they also keep a slot writable. `CRISPProgram` cannot check the first rule — only - /// this runs late enough to — so anyone can leave an entry nobody else can open. Because such - /// an entry is never selected, it is never a valid parent either, and the next honest input - /// names the same parent it did and is taken in its place. Without that, a slot could be frozen - /// against masking, and a slot that cannot be masked is one where every later input is provably - /// its owner voting again — a receipt, which is what masks exist to prevent. - /// - /// A slot whose entries are all unusable contributes nothing — it never held a good vote. - pub fn chain_head_per_slot(inputs: &[PublishedInput]) -> Vec { - let mut head: BTreeMap<[u8; 20], u64> = BTreeMap::new(); - let mut selected_for_slot: BTreeMap<[u8; 20], usize> = BTreeMap::new(); - - // In index order, which is the order the tree was built in, so a chain is only ever - // extended forwards. - for input in inputs { - if !input.matches_commitment() { - continue; - } - - let Ok(metadata) = metadata_of(input) else { - continue; - }; - - if metadata.parent != head.get(&metadata.slot).copied() { - continue; - } - - head.insert(metadata.slot, input.index as u64); - selected_for_slot.insert(metadata.slot, input.index); - } - - let mut selected: Vec = selected_for_slot.into_values().collect(); - selected.sort_unstable(); - selected - } - - /// The policy `CRISPProgram` requires. - pub fn crisp() -> InputPolicy { - InputPolicy { - leaf, - select: chain_head_per_slot, - } - } -} diff --git a/crates/support/scripts/container/build.sh b/crates/support/scripts/container/build.sh deleted file mode 100755 index f56e293822..0000000000 --- a/crates/support/scripts/container/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -exec cargo build --locked --release --manifest-path /app/crates/support/Cargo.toml diff --git a/crates/support/scripts/container/start.sh b/crates/support/scripts/container/start.sh deleted file mode 100755 index a7d82dbb7a..0000000000 --- a/crates/support/scripts/container/start.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -: "${OPENVM_PROVER_BIN:?Set OPENVM_PROVER_BIN}" -: "${OPENVM_PROVER_CONFIG:?Set OPENVM_PROVER_CONFIG}" -exec cargo run --locked --release --manifest-path /app/crates/support/Cargo.toml -p e3-support-app -- "$@" diff --git a/crates/support/types/Cargo.toml b/crates/support/types/Cargo.toml deleted file mode 100644 index a6cbc716d4..0000000000 --- a/crates/support/types/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "e3-support-types" -version.workspace = true -edition.workspace = true - -[dependencies] -serde.workspace = true -serde_json.workspace = true -anyhow.workspace = true -hex.workspace = true -derivative = "=2.2.0" -e3-compute-provider.workspace = true -alloy-primitives.workspace = true diff --git a/crates/support/types/src/lib.rs b/crates/support/types/src/lib.rs deleted file mode 100644 index 59319403ba..0000000000 --- a/crates/support/types/src/lib.rs +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use alloy_primitives::U256; -use anyhow::Result; -use derivative::Derivative; -use e3_compute_provider::{ComputeInput, ComputeResult}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ComputeDomain { - pub chain_id: u64, - pub verifying_contract: [u8; 20], - pub e3_id: [u8; 32], - pub encryption_scheme_id: [u8; 32], - pub committee_public_key_hash: [u8; 32], -} - -impl ComputeDomain { - pub fn new( - chain_id: u64, - interfold_address: &str, - e3_id: &str, - encryption_scheme_id: &[u8], - committee_public_key_hash: &[u8], - ) -> std::result::Result { - Ok(Self { - chain_id, - verifying_contract: fixed( - &hex::decode(interfold_address.trim_start_matches("0x")) - .map_err(|error| format!("invalid Interfold address: {error}"))?, - "Interfold address", - )?, - e3_id: e3_id - .parse::() - .map_err(|error| format!("invalid E3 ID: {error}"))? - .to_be_bytes(), - encryption_scheme_id: fixed(encryption_scheme_id, "encryption scheme ID")?, - committee_public_key_hash: fixed( - committee_public_key_hash, - "committee public key hash", - )?, - }) - } -} - -fn fixed(value: &[u8], name: &str) -> std::result::Result<[u8; N], String> { - value - .try_into() - .map_err(|_| format!("{name} must be {N} bytes")) -} - -fn uint_word(value: u64) -> Vec { - let mut word = vec![0_u8; 32]; - word[24..].copy_from_slice(&value.to_be_bytes()); - word -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ComputeGuestInput { - pub domain: ComputeDomain, - pub input: ComputeInput, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ComputeJournal { - pub chain_id: Vec, - pub verifying_contract: Vec, - pub e3_id: Vec, - pub encryption_scheme_id: Vec, - pub committee_public_key_hash: Vec, - pub ciphertext_hash: Vec, - pub ciphertext_commitment: Vec, - pub params_hash: Vec, - pub merkle_root: Vec, -} - -impl ComputeJournal { - /// Encode the nine journal fields as Solidity ABI words. - pub fn abi_bytes(&self) -> std::result::Result, String> { - let fields = [ - &self.chain_id, - &self.verifying_contract, - &self.e3_id, - &self.encryption_scheme_id, - &self.committee_public_key_hash, - &self.ciphertext_hash, - &self.ciphertext_commitment, - &self.params_hash, - &self.merkle_root, - ]; - if fields.iter().any(|field| field.len() != 32) { - return Err("Each journal field must contain 32 bytes".into()); - } - Ok(fields - .into_iter() - .flat_map(|field| field.iter().copied()) - .collect()) - } - - pub fn new(domain: ComputeDomain, result: ComputeResult) -> std::result::Result { - for (name, value) in [ - ("ciphertext hash", &result.ciphertext_hash), - ("ciphertext commitment", &result.ciphertext_commitment), - ("parameter hash", &result.params_hash), - ("input root", &result.merkle_root), - ] { - if value.len() != 32 { - return Err(format!("{name} must be 32 bytes")); - } - } - - Ok(Self { - chain_id: uint_word(domain.chain_id), - verifying_contract: [vec![0_u8; 12], domain.verifying_contract.to_vec()].concat(), - e3_id: domain.e3_id.to_vec(), - encryption_scheme_id: domain.encryption_scheme_id.to_vec(), - committee_public_key_hash: domain.committee_public_key_hash.to_vec(), - ciphertext_hash: result.ciphertext_hash, - ciphertext_commitment: result.ciphertext_commitment, - params_hash: result.params_hash, - merkle_root: result.merkle_root, - }) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ComputeResponse { - pub ciphertext: Vec, - pub proof: Vec, -} - -#[derive(Debug, Deserialize)] -pub struct ComputeRequest { - pub e3_id: Option, - pub chain_id: u64, - pub interfold_address: String, - #[serde(deserialize_with = "deserialize_hex_string")] - pub encryption_scheme_id: Vec, - #[serde(deserialize_with = "deserialize_hex_string")] - pub committee_public_key_hash: Vec, - #[serde(deserialize_with = "deserialize_hex_string")] - pub params: Vec, - #[serde(deserialize_with = "deserialize_hex_tuple")] - pub ciphertext_inputs: Vec<(Vec, u64)>, - pub callback_url: Option, - - // What the E3 program published alongside each ciphertext. A program whose contract folds more - // than the ciphertext into its input-tree leaf needs these to rebuild the same leaf; without - // them the guest derives a different root and the proof cannot be published. Optional, because - // a program using the default policy publishes none of it — but silently dropping them when - // they *are* sent is the failure this exists to prevent, so the handler rejects a partial set - // rather than computing a root the contract will reject. - #[serde(default)] - pub input_commitments: Vec, - #[serde(default)] - pub input_slots: Vec, - #[serde(default)] - pub input_parents: Vec, -} - -/// Webhook payload for CRISP and `E3ProgramServer`. -/// A completed payload includes the ciphertext, its journal-bound commitment, and the proof. -/// A failed payload includes the E3 ID and an error message. -#[derive(Derivative, Serialize, Deserialize)] -#[derivative(Debug)] -#[serde(tag = "status", rename_all = "lowercase")] -pub enum WebhookPayload { - Completed { - e3_id: String, - #[serde(serialize_with = "serialize_as_hex")] - #[serde(deserialize_with = "deserialize_hex_string")] - #[derivative(Debug = "ignore")] - ciphertext: Vec, - #[serde(serialize_with = "serialize_as_hex")] - #[serde(deserialize_with = "deserialize_hex_string")] - #[derivative(Debug = "ignore")] - ciphertext_commitment: Vec, - #[serde(serialize_with = "serialize_as_hex")] - #[serde(deserialize_with = "deserialize_hex_string")] - #[derivative(Debug = "ignore")] - proof: Vec, - }, - Failed { - e3_id: String, - error: String, - }, -} - -fn serialize_as_hex(bytes: &Vec, serializer: S) -> Result -where - S: Serializer, -{ - let hex_string = format!("0x{}", hex::encode(bytes)); - serializer.serialize_str(&hex_string) -} - -pub fn deserialize_hex_string<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: String = Deserialize::deserialize(deserializer)?; - let hex_str = s.strip_prefix("0x").unwrap_or(&s); - hex::decode(hex_str).map_err(serde::de::Error::custom) -} - -pub fn deserialize_hex_tuple<'de, D>(deserializer: D) -> Result, u64)>, D::Error> -where - D: Deserializer<'de>, -{ - let tuples: Vec<(String, u64)> = Deserialize::deserialize(deserializer)?; - tuples - .into_iter() - .map(|(hex_str, num)| { - let stripped = hex_str.strip_prefix("0x").unwrap_or(&hex_str); - hex::decode(stripped) - .map(|bytes| (bytes, num)) - .map_err(serde::de::Error::custom) - }) - .collect() -} - -#[cfg(test)] -mod tests { - use crate::{ComputeDomain, ComputeRequest, WebhookPayload}; - - #[test] - fn compute_domain_preserves_ids_larger_than_u64() { - let domain = ComputeDomain::new( - 1, - "0x1111111111111111111111111111111111111111", - "18446744073709551616", - &[0x22; 32], - &[0x33; 32], - ) - .unwrap(); - - assert_eq!(domain.e3_id[23], 1); - assert!(domain.e3_id[..23].iter().all(|byte| *byte == 0)); - assert!(domain.e3_id[24..].iter().all(|byte| *byte == 0)); - } - - #[test] - fn test_deserialize_compute_request() { - let json = r#" - { - "e3_id": "12345", - "chain_id": 31337, - "interfold_address": "0x1111111111111111111111111111111111111111", - "encryption_scheme_id": "0x2222222222222222222222222222222222222222222222222222222222222222", - "committee_public_key_hash": "0x3333333333333333333333333333333333333333333333333333333333333333", - "params": "0x12345ffa", - "ciphertext_inputs": [ - ["0xffabc123", 100], - ["0xaa6de432", 200] - ], - "callback_url": "https://example.com/callback" - } - "#; - - let payload: ComputeRequest = serde_json::from_str(json).unwrap(); - - assert_eq!(payload.e3_id, Some("12345".to_string())); - assert_eq!(payload.chain_id, 31337); - assert_eq!( - payload.interfold_address, - "0x1111111111111111111111111111111111111111" - ); - assert_eq!(payload.encryption_scheme_id, vec![0x22; 32]); - assert_eq!(payload.committee_public_key_hash, vec![0x33; 32]); - assert_eq!(payload.params, hex::decode("12345ffa").unwrap()); - assert_eq!(payload.ciphertext_inputs.len(), 2); - assert_eq!( - payload.ciphertext_inputs[0], - (hex::decode("ffabc123").unwrap(), 100) - ); - assert_eq!( - payload.ciphertext_inputs[1], - (hex::decode("aa6de432").unwrap(), 200) - ); - assert_eq!( - payload.callback_url, - Some("https://example.com/callback".to_string()) - ); - } - - #[test] - fn test_deserialize_compute_request_no_prefix() { - let json = r#" - { - "e3_id": "12345", - "chain_id": 31337, - "interfold_address": "0x1111111111111111111111111111111111111111", - "encryption_scheme_id": "2222222222222222222222222222222222222222222222222222222222222222", - "committee_public_key_hash": "3333333333333333333333333333333333333333333333333333333333333333", - "params": "12345ffa", - "ciphertext_inputs": [ - ["ffabc123", 100], - ["aa6de432", 200] - ], - "callback_url": "https://example.com/callback" - } - "#; - - let payload: ComputeRequest = serde_json::from_str(json).unwrap(); - - assert_eq!(payload.e3_id, Some("12345".to_string())); - assert_eq!(payload.encryption_scheme_id, vec![0x22; 32]); - assert_eq!(payload.committee_public_key_hash, vec![0x33; 32]); - assert_eq!(payload.params, hex::decode("12345ffa").unwrap()); - assert_eq!(payload.ciphertext_inputs.len(), 2); - assert_eq!( - payload.ciphertext_inputs[0], - (hex::decode("ffabc123").unwrap(), 100) - ); - assert_eq!( - payload.ciphertext_inputs[1], - (hex::decode("aa6de432").unwrap(), 200) - ); - assert_eq!( - payload.callback_url, - Some("https://example.com/callback".to_string()) - ); - } - - #[test] - fn test_webhook_payload_serialization_completed() { - let payload = WebhookPayload::Completed { - e3_id: "12345".to_string(), - ciphertext: vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], - ciphertext_commitment: vec![0x11; 32], - proof: vec![0xde, 0xad, 0xbe, 0xef], - }; - - let json = serde_json::to_string(&payload).expect("Failed to serialize"); - let expected = format!( - r#"{{"status":"completed","e3_id":"12345","ciphertext":"0x0123456789abcdef","ciphertext_commitment":"0x{}","proof":"0xdeadbeef"}}"#, - "11".repeat(32) - ); - - assert_eq!(json, expected); - } - - #[test] - fn test_webhook_payload_serialization_failed() { - let payload = WebhookPayload::Failed { - e3_id: "12345".to_string(), - error: "Computation failed".to_string(), - }; - - let json = serde_json::to_string(&payload).expect("Failed to serialize"); - let expected = r#"{"status":"failed","e3_id":"12345","error":"Computation failed"}"#; - - assert_eq!(json, expected); - } - - #[test] - fn test_webhook_deserialize_roundtrip() { - let json = format!( - r#"{{"status":"completed","e3_id":"12345","ciphertext":"0xabcdef","ciphertext_commitment":"0x{}","proof":"0x123456"}}"#, - "22".repeat(32) - ); - let payload: WebhookPayload = serde_json::from_str(&json).unwrap(); - match payload { - WebhookPayload::Completed { - e3_id, - ciphertext, - ciphertext_commitment, - proof, - } => { - assert_eq!(e3_id, "12345"); - assert_eq!(ciphertext, vec![0xab, 0xcd, 0xef]); - assert_eq!(ciphertext_commitment, vec![0x22; 32]); - assert_eq!(proof, vec![0x12, 0x34, 0x56]); - } - _ => panic!("Expected Completed"), - } - } -} diff --git a/examples/CRISP/.interfold/support/openvm b/examples/CRISP/.interfold/support/openvm new file mode 120000 index 0000000000..c63cdf9dbf --- /dev/null +++ b/examples/CRISP/.interfold/support/openvm @@ -0,0 +1 @@ +../../../../crates/support-scripts/openvm \ No newline at end of file diff --git a/examples/CRISP/Cargo.lock b/examples/CRISP/Cargo.lock index 8beb770f02..1096d9ee65 100644 --- a/examples/CRISP/Cargo.lock +++ b/examples/CRISP/Cargo.lock @@ -2935,6 +2935,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "openvm-keccak256", + "rayon", "serde", "sha2 0.10.9", "sha3", @@ -3008,6 +3009,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "e3-openvm-host" +version = "0.19.0-test.2" +dependencies = [ + "anyhow", + "e3-compute-provider", + "e3-openvm-types", + "tempfile", + "tokio", +] + +[[package]] +name = "e3-openvm-types" +version = "0.19.0-test.2" +dependencies = [ + "bincode", + "e3-compute-provider", + "serde", +] + [[package]] name = "e3-parity-matrix" version = "0.19.0-test.2" @@ -3079,6 +3100,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "e3-support-scripts-openvm" +version = "0.1.0" +dependencies = [ + "anyhow", + "e3-openvm-host", + "e3-program-server", + "e3-user-program", + "tokio", +] + [[package]] name = "e3-user-program" version = "0.1.0" @@ -7421,15 +7453,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.27.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] diff --git a/examples/CRISP/Cargo.toml b/examples/CRISP/Cargo.toml index 8c268c5d9f..c5ad85b361 100644 --- a/examples/CRISP/Cargo.toml +++ b/examples/CRISP/Cargo.toml @@ -2,6 +2,7 @@ members = [ "server", ".interfold/support/dev", + ".interfold/support/openvm/service", "program", "crates/zk-inputs", "crates/zk-inputs-wasm", @@ -34,6 +35,7 @@ bincode = { version = "=1.3.3" } bytemuck = { version = "=1.23.1" } derivative = "=2.2.0" e3-compute-provider = { path = "../../crates/compute-provider" } +e3-openvm-host = { path = "../../crates/openvm-host" } e3-data-availability = { path = "../../crates/data-availability" } e3-program-server = { path = "../../crates/program-server" } e3-bfv-client = { path = "../../crates/bfv-client" } diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index dc14686ef2..bd59cb94e0 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -54,15 +54,16 @@ Before getting started, ensure you have installed: - `nargo`: `noirup -v v1.0.0-beta.26` (`NOIR_TOOLCHAIN` in `.github/workflows/ci.yml`) - `bb`: version and per-platform checksums live in `crates/zk-prover/versions.json` -The program server uses OpenVM by default. Before startup, build the guest and worker, prepare the -keys, and configure `program.openvm` in `interfold.config.yaml`. Follow -[`crates/support/openvm/README.md`](../../crates/support/openvm/README.md). The CUDA worker needs a -compatible Linux GPU environment; the native HTTP service has no CUDA dependency. +Local development runs the unproved development runner unless `CRISP_REAL_PROOFS=1` (see +`crisp.dev.env.example`). Real proofs use OpenVM: build the workers, configure `program.openvm` in +`interfold.config.yaml`, and run `interfold program compile`. Follow +[`crates/openvm-prover/README.md`](../../crates/openvm-prover/README.md). A machine with a working +CUDA GPU proves on it when the CUDA worker is configured; any other machine proves on the CPU. -Deployment also requires `OPENVM_APP_EXE_COMMIT`, `OPENVM_APP_VM_COMMIT`, and either -`OPENVM_VERIFIER_ARTIFACT` with `OPENVM_VERIFIER_SHA256`, or `OPENVM_HALO2_VERIFIER` with -`OPENVM_HALO2_RUNTIME_CODE_HASH`. These values must describe the worker's actual artifacts. The -CRISP deployment never selects a mock compute verifier. +The CRISP deployment reads the receipt identity `interfold program compile` wrote, unless +`OPENVM_APP_EXE_COMMIT`, `OPENVM_APP_VM_COMMIT`, and either `OPENVM_VERIFIER_ARTIFACT` with +`OPENVM_VERIFIER_SHA256` or `OPENVM_HALO2_VERIFIER` with `OPENVM_HALO2_RUNTIME_CODE_HASH` are set. +Outside `CRISP_UNPROVED_TEST=1` on the local chain, it never selects a mock compute verifier. ## Quick Start @@ -139,23 +140,20 @@ pnpm test:e2e ### Ciphernode Configuration -The `interfold.config.yaml` file in the CRISP root directory configures the ciphernode network. By -default, it runs in development mode with fake proofs for fast local development: - -```yaml -program: - dev: true # Uses fake zkVM proofs (fast for development) -``` +The `interfold.config.yaml` file in the CRISP root directory configures the ciphernode network. It +sets `program.dev: false`. The local scripts override that with `E3_PROGRAM__DEV=true` unless +`CRISP_REAL_PROOFS=1`, so a local round uses the unproved development runner by default. ### OpenVM configuration -The real-proof compute service now uses OpenVM. Follow the -[OpenVM build and migration guide](../../crates/support/openvm/README.md) to build the guest and -worker, derive the application identity, and configure proving artifacts. +The real-proof compute service uses OpenVM. CRISP's guest is `examples/CRISP/guest`, and its +service is `.interfold/support/openvm`; both link `program/`, the processor and policy the contract +agrees with. Follow the [OpenVM guide](../../crates/openvm-prover/README.md) to build the workers, +then run `interfold program compile` for the guest, keys, identity and service. -Set `program.dev: false` and supply deployment-local `program.openvm.repository`, -`program.openvm.prover_bin`, and `program.openvm.prover_config` paths. Do not put account keys, -proving artifacts, or machine-specific values in the shared configuration. +Set `program.dev: false` and supply deployment-local `program.openvm.prover_bin` and, on a GPU +machine, `program.openvm.prover_bin_cuda` paths. Do not put account keys, proving artifacts, or +machine-specific values in the shared configuration. A new OpenVM deployment requires matching receipt and ciphertext-duty verifiers. Existing RISC Zero deployments do not become compatible by changing the service configuration. Drain active rounds and diff --git a/crates/support/openvm/guest/Cargo.lock b/examples/CRISP/guest/Cargo.lock similarity index 99% rename from crates/support/openvm/guest/Cargo.lock rename to examples/CRISP/guest/Cargo.lock index 1e70c8fe30..c8f3baef1d 100644 --- a/crates/support/openvm/guest/Cargo.lock +++ b/examples/CRISP/guest/Cargo.lock @@ -1159,6 +1159,29 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "e3-openvm-guest" +version = "0.1.0" +dependencies = [ + "e3-compute-provider", + "e3-openvm-types", + "e3-safe", + "e3-user-program", + "openvm", + "openvm-algebra-guest", + "openvm-sha2", + "sha2", +] + +[[package]] +name = "e3-openvm-types" +version = "0.19.0-test.2" +dependencies = [ + "bincode", + "e3-compute-provider", + "serde", +] + [[package]] name = "e3-parity-matrix" version = "0.19.0-test.2" @@ -1195,19 +1218,6 @@ dependencies = [ "taceo-poseidon2", ] -[[package]] -name = "e3-support-types" -version = "0.1.0" -dependencies = [ - "alloy-primitives", - "anyhow", - "derivative", - "e3-compute-provider", - "hex", - "serde", - "serde_json", -] - [[package]] name = "e3-user-program" version = "0.1.0" @@ -1216,7 +1226,6 @@ dependencies = [ "e3-fhe-params", "fhe", "fhe-traits", - "openvm-keccak256", "openvm-sha2", "sha2", "sha3 0.10.8", @@ -1733,21 +1742,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "interfold-openvm-guest" -version = "0.1.0" -dependencies = [ - "bincode", - "e3-compute-provider", - "e3-safe", - "e3-support-types", - "e3-user-program", - "openvm", - "openvm-algebra-guest", - "openvm-sha2", - "sha2", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" diff --git a/crates/support/openvm/guest/Cargo.toml b/examples/CRISP/guest/Cargo.toml similarity index 50% rename from crates/support/openvm/guest/Cargo.toml rename to examples/CRISP/guest/Cargo.toml index bceef9ffad..7e52d1c08c 100644 --- a/crates/support/openvm/guest/Cargo.toml +++ b/examples/CRISP/guest/Cargo.toml @@ -1,21 +1,22 @@ [package] -name = "interfold-openvm-guest" +name = "e3-openvm-guest" version = "0.1.0" edition = "2021" license = "LGPL-3.0-only" +# Proves this project's E3 program. Built for the OpenVM target with `cargo openvm build` +# (see `.interfold/support/openvm/compile`), so it is a workspace of its own. [workspace] resolver = "3" [dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", features = ["std", "heap-embedded-alloc"] } -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } -e3-support-types = { path = "../../types" } -e3-user-program = { path = "../../program", features = ["openvm-hashes"] } -e3-compute-provider = { path = "../../../compute-provider", features = ["openvm-hashes"] } -e3-safe = { path = "../../../safe", features = ["openvm"] } -bincode = "=1.3.3" +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +e3-user-program = { path = "../program", features = ["openvm-hashes"] } +e3-compute-provider = { path = "../../../crates/compute-provider" } +e3-openvm-types = { path = "../../../crates/openvm-types" } +e3-safe = { path = "../../../crates/safe", features = ["openvm"] } sha2 = "=0.10.9" [profile.release] diff --git a/crates/support/openvm/guest/openvm.toml b/examples/CRISP/guest/openvm.toml similarity index 100% rename from crates/support/openvm/guest/openvm.toml rename to examples/CRISP/guest/openvm.toml diff --git a/examples/CRISP/guest/src/main.rs b/examples/CRISP/guest/src/main.rs new file mode 100644 index 0000000000..6bfbd14d3b --- /dev/null +++ b/examples/CRISP/guest/src/main.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! The OpenVM guest that proves this project's Secure Process. +//! +//! It reads the round one item at a time: a header, every ciphertext in index order, then the +//! ciphertexts the program's policy selected, again in index order. Only one ciphertext is held at +//! a time, so the round can be larger than the guest's memory. It reveals the SHA-256 digest of the +//! nine-word journal, which the receipt verifier recomputes on chain. + +openvm::init!(); + +use e3_compute_provider::SecureProcess; +use e3_openvm_types::{ComputeJournal, GuestHeader}; +use sha2::Digest; + +fn main() { + let header = GuestHeader::decode(&openvm::io::read_vec()).expect("Invalid guest header"); + let inputs = header.indices.len(); + let mut process = SecureProcess::new( + &header.params, + header.indices, + header.published, + e3_user_program::policy(), + ) + .expect("Invalid round"); + for _ in 0..inputs { + process + .absorb(&openvm::io::read_vec()) + .expect("Invalid input"); + } + let (result, _) = process + .select() + .expect("Input selection failed") + .finish(e3_user_program::fhe_processor, |_| { + Ok(openvm::io::read_vec()) + }) + .expect("Ciphertext aggregation failed"); + + let journal = ComputeJournal::new(&header.domain, &result) + .expect("Invalid compute journal") + .abi_bytes(); + let digest = openvm_sha2::Sha256::digest(&journal); + for (index, word) in digest.chunks_exact(4).enumerate() { + openvm::io::reveal_u32(u32::from_le_bytes(word.try_into().unwrap()), index); + } +} diff --git a/examples/CRISP/interfold.config.yaml b/examples/CRISP/interfold.config.yaml index 4e8798a0cd..413ef4ba48 100644 --- a/examples/CRISP/interfold.config.yaml +++ b/examples/CRISP/interfold.config.yaml @@ -85,8 +85,12 @@ chains: deploy_block: 11856142 program: dev: false - # Real proofs use program.openvm. Configure repository, prover_bin, - # and prover_config as deployment-local absolute paths. See crates/support/openvm/README.md. + # Real proofs use program.openvm, with absolute paths local to the deployment: + # openvm: + # prover_bin: /path/to/interfold-openvm-prover # the CPU worker + # prover_bin_cuda: /path/to/interfold-openvm-prover-cuda # optional; used when a GPU works + # backend: auto # auto, cpu or cuda + # See crates/openvm-prover/README.md. # The scheduler defaults to 2 concurrent jobs and reserves 2 logical CPUs for Actix / libp2p. # It reduces concurrency when the host or cgroup memory limit is too small. # Example override on a dedicated 64 GB host: diff --git a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts index 9b66d173e8..16578eee38 100644 --- a/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts +++ b/examples/CRISP/packages/crisp-contracts/deploy/crisp.ts @@ -7,6 +7,7 @@ import { AVAIL_FINALIZATION_WINDOW_SECONDS, AVAIL_VECTORX, + compiledOpenVmEnvironment, deployOpenVmReceiptVerifier, getDeploymentChain, readDeploymentArgs, @@ -15,6 +16,8 @@ import { import { Interfold__factory as InterfoldFactory } from '@interfold/contracts/types' import hre from 'hardhat' +import path from 'node:path' +import { fileURLToPath } from 'node:url' import { CRISPProgram__factory as CRISPProgramFactory } from '../types' import { verifierNames } from '../scripts/verifiers' @@ -333,7 +336,13 @@ export const deployVerifier = async (_useMockVerifier: boolean, connectedEthers? storeDeploymentArgs({ address, blockNumber: await ethers.provider.getBlockNumber() }, 'MockOpenVmReceiptVerifier', chain) return address } - const { receipt: verifier, halo2Verifier, halo2RuntimeCodeHash, appExeCommit, appVmCommit } = await deployOpenVmReceiptVerifier(ethers) + // The identity `interfold program compile` wrote for examples/CRISP, unless OPENVM_* settings name + // one. + const crispRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..') + const { receipt: verifier, halo2Verifier, halo2RuntimeCodeHash, appExeCommit, appVmCommit } = await deployOpenVmReceiptVerifier( + ethers, + compiledOpenVmEnvironment(crispRoot), + ) storeDeploymentArgs( { address: halo2Verifier, blockNumber: await ethers.provider.getBlockNumber(), bytecodeHash: halo2RuntimeCodeHash }, 'OpenVmHalo2Verifier', diff --git a/examples/CRISP/program/README.md b/examples/CRISP/program/README.md index 9dccb04c3b..10b3452a1e 100644 --- a/examples/CRISP/program/README.md +++ b/examples/CRISP/program/README.md @@ -22,8 +22,10 @@ reference. Both the protocol and application verifier must pass before the E3 re ## Build and run -Follow [the OpenVM instructions](../../../crates/support/openvm/README.md). Configure -`program.openvm` with the repository, worker, and worker-configuration paths. +Follow [the OpenVM instructions](../../../crates/openvm-prover/README.md). Configure +`program.openvm` with the worker paths, then run `interfold program compile` in `examples/CRISP`. +The guest in `examples/CRISP/guest` and the service in `.interfold/support/openvm` both link this +crate. From `examples/CRISP`, run: diff --git a/examples/CRISP/program/src/lib.rs b/examples/CRISP/program/src/lib.rs index bf4868600c..0f02f8ae57 100644 --- a/examples/CRISP/program/src/lib.rs +++ b/examples/CRISP/program/src/lib.rs @@ -17,10 +17,13 @@ pub fn policy() -> e3_compute_provider::InputPolicy { } /// CRISP Implementation of the CiphertextProcessor function -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +/// +/// Adds the selected ballots one at a time, so only the running sum and the ballot being added are +/// held in memory. +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -33,8 +36,7 @@ pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { /// Both are specific to this program and its contract. They live here, beside the `CRISPProgram` /// they must agree with, rather than in `e3-compute-provider`, which every E3 program shares. pub mod policy { - use e3_compute_provider::hashing::keccak256; - use e3_compute_provider::policy::{PublishedInput, leaf_from_digest}; + use e3_compute_provider::policy::{leaf_from_digest, InputRecord, PublishedInput}; use e3_compute_provider::{ComputeError, InputPolicy}; #[cfg(feature = "openvm-hashes")] use openvm_sha2::Sha256; @@ -54,24 +56,24 @@ pub mod policy { parent: Option, } - /// Splits the published metadata, which is `slot || parentIndexPlusOne` as + /// Splits the published metadata of input `index`, which is `slot || parentIndexPlusOne` as /// `abi.encodePacked(address, uint40)` lays it out. - fn metadata_of(input: &PublishedInput) -> Result { - if input.metadata.len() != METADATA_LEN { + fn metadata_of(index: usize, metadata: &[u8]) -> Result { + if metadata.len() != METADATA_LEN { return Err(ComputeError::LeafCommitment { - index: input.index, + index, reason: format!( "expected {METADATA_LEN} bytes of slot and parent, got {}", - input.metadata.len() + metadata.len() ), }); } let mut slot = [0u8; 20]; - slot.copy_from_slice(&input.metadata[..20]); + slot.copy_from_slice(&metadata[..20]); let mut parent_plus_one: u64 = 0; - for byte in &input.metadata[20..] { + for byte in &metadata[20..] { parent_plus_one = (parent_plus_one << 8) | u64::from(*byte); } @@ -97,10 +99,11 @@ pub mod policy { })?; // Hashed as published rather than as parsed, so the leaf cannot drift from the contract's // `abi.encodePacked` layout. Parsed first only to refuse the wrong length. - metadata_of(input)?; + metadata_of(input.index, input.metadata)?; + // `ciphertext_hash` is `keccak256(input.ciphertext)`, computed once by the Secure Process. let mut outer = Sha256::new(); - outer.update(keccak256(input.ciphertext)); + outer.update(input.ciphertext_hash); outer.update(commitment); outer.update(input.metadata); Ok(leaf_from_digest(&outer.finalize())) @@ -130,7 +133,7 @@ pub mod policy { /// its owner voting again — a receipt, which is what masks exist to prevent. /// /// A slot whose entries are all unusable contributes nothing — it never held a good vote. - pub fn chain_head_per_slot(inputs: &[PublishedInput]) -> Vec { + pub fn chain_head_per_slot(inputs: &[InputRecord]) -> Vec { let mut head: BTreeMap<[u8; 20], u64> = BTreeMap::new(); let mut selected_for_slot: BTreeMap<[u8; 20], usize> = BTreeMap::new(); @@ -141,7 +144,7 @@ pub mod policy { continue; } - let Ok(metadata) = metadata_of(input) else { + let Ok(metadata) = metadata_of(input.index, input.metadata) else { continue; }; diff --git a/examples/CRISP/program/tests/input_leaf.rs b/examples/CRISP/program/tests/input_leaf.rs index 40f39b247b..d4feca5d36 100644 --- a/examples/CRISP/program/tests/input_leaf.rs +++ b/examples/CRISP/program/tests/input_leaf.rs @@ -11,6 +11,7 @@ //! failure has no other symptom. Neither language can catch a divergence alone, so both check the //! same vector and one of them fails when either side moves. +use e3_compute_provider::hashing::keccak256; use e3_compute_provider::policy::PublishedInput; use e3_user_program::policy::leaf; use num_bigint::BigUint; @@ -37,6 +38,7 @@ fn leaf_of(ciphertext: &[u8], commitment: &[u8; 32], metadata: &[u8]) -> String leaf(&PublishedInput { index: 0, ciphertext, + ciphertext_hash: keccak256(ciphertext), commitment: Some(commitment), metadata, recomputed: None, @@ -96,6 +98,7 @@ fn metadata_of_the_wrong_length_is_refused() { let result = leaf(&PublishedInput { index: 0, ciphertext: &bytes, + ciphertext_hash: keccak256(&bytes), commitment: Some(&COMMITMENT), metadata: &SLOT, recomputed: None, diff --git a/examples/CRISP/program/tests/onchain_root_agreement.rs b/examples/CRISP/program/tests/onchain_root_agreement.rs index 516d2d3fc8..2300067447 100644 --- a/examples/CRISP/program/tests/onchain_root_agreement.rs +++ b/examples/CRISP/program/tests/onchain_root_agreement.rs @@ -79,11 +79,7 @@ fn rust_reproduces_the_root_the_contract_produced() { |inputs| { // Membership of the tree is what this test asserts, so the processor only has to be // deterministic over the selected set. - inputs - .ciphertexts - .iter() - .flat_map(|(bytes, _)| bytes.clone()) - .collect() + inputs.ciphertexts.flat_map(|(bytes, _)| bytes).collect() }, crisp(), ) @@ -162,13 +158,7 @@ fn rust_selects_the_honest_mask_that_follows_a_poisoned_one() { published, } .process( - |inputs| { - inputs - .ciphertexts - .iter() - .flat_map(|(bytes, _)| bytes.clone()) - .collect() - }, + |inputs| inputs.ciphertexts.flat_map(|(bytes, _)| bytes).collect(), crisp(), ) .expect("a poisoned append must not stop the round"); @@ -230,13 +220,7 @@ fn rust_tallies_the_re_vote() { published, } .process( - |inputs| { - inputs - .ciphertexts - .iter() - .flat_map(|(bytes, _)| bytes.clone()) - .collect() - }, + |inputs| inputs.ciphertexts.flat_map(|(bytes, _)| bytes).collect(), crisp(), ) .expect("a round with a re-vote must process"); diff --git a/examples/CRISP/program/tests/secure_process.rs b/examples/CRISP/program/tests/secure_process.rs index b5bc49a7c4..6e62e54a27 100644 --- a/examples/CRISP/program/tests/secure_process.rs +++ b/examples/CRISP/program/tests/secure_process.rs @@ -6,13 +6,15 @@ //! Runs the CRISP Secure Process natively, outside the OpenVM guest. //! -//! The guest is one line — `input.input.process(fhe_processor, crisp())` — so calling that here -//! exercises the same code the zkVM runs, with the real CRISP processor and the real CRISP policy. +//! The guest feeds a streamed round through `SecureProcess` with `fhe_processor` and `crisp()`, and +//! `ComputeInput::process` runs the same `SecureProcess` over a round held in memory. Calling it +//! here exercises the code the zkVM runs, with the real CRISP processor and the real CRISP policy. //! Everything except proof generation is covered, which matters because a guest failure inside the -//! zkVM surfaces only as a missing proof and a requester-billed compute timeout. +//! zkVM surfaces only as a missing proof. use e3_compute_provider::{ - ComputeError, ComputeInput, ComputeResult, FHEInputs, FHEProcessorInput, PublishedData, + Batching, ComputeError, ComputeInput, ComputeResult, FHEInputs, FHEProcessorInput, + PublishedData, SecureProcess, }; use e3_fhe_params::{build_pair_for_preset, encode_bfv_params, BfvPreset}; use e3_user_program::fhe_processor; @@ -118,8 +120,8 @@ impl Round { } fn aggregate(&self, inputs: &FHEInputs) -> Vec { - fhe_processor(&FHEProcessorInput { - ciphertexts: &inputs.ciphertexts, + fhe_processor(FHEProcessorInput { + ciphertexts: &mut inputs.ciphertexts.iter().cloned(), params: &self.params, }) } @@ -332,3 +334,84 @@ fn an_honest_re_vote_replaces_the_earlier_ballot() { round.run(reference_input).unwrap().ciphertext_hash ); } + +/// The guest reads a round one ciphertext at a time, twice; the host holds the whole round. On a +/// round with a re-vote, a poisoned append, a contradicting input and garbage bytes, both must reach +/// the same selection, root, tally and journal values, or the host predicts a journal the guest +/// never proves. +#[test] +fn a_streamed_round_matches_the_held_round() { + let round = Round::new(); + let voter = Round::slot(2); + let victim = Round::slot(7); + let first = round.ballot(&[1, 0], 1); + let second = round.ballot(&[0, 7], 2); + + let mut input = round.round_input_at( + vec![ + first, + round.ballot(&[6, 0], 3), + round.ballot(&[2, 0], 4), + round.ballot(&[0, 1], 5), + ], + vec![voter, victim, Round::slot(3), Round::slot(4)], + ); + // A contradicting input: a proven commitment beside bytes that are not its ciphertext. + input.fhe_inputs.ciphertexts[2].0 = round.ballot(&[0, 99], 9); + // Garbage bytes. + input.fhe_inputs.ciphertexts[3].0 = vec![0xff; 32]; + // An honest re-vote of slot 2, and a poisoned append to slot 7. + input.fhe_inputs.ciphertexts.push((second.clone(), 4)); + input.published.push(PublishedData { + commitment: Some(round.commitment(&second)), + metadata: Round::metadata(voter, Some(0)), + }); + let reused = input.published[1].commitment; + input + .fhe_inputs + .ciphertexts + .push((round.ballot(&[0, 9], 6), 5)); + input.published.push(PublishedData { + commitment: reused, + metadata: Round::metadata(victim, Some(1)), + }); + + let (held, held_tally, held_selection) = input + .run_selected(fhe_processor, crisp(), Batching::Parallel { batch_size: 2 }) + .unwrap(); + assert_eq!( + held_selection, + vec![1, 4], + "the victim's vote and the re-vote" + ); + + let mut process = SecureProcess::new( + &input.fhe_inputs.params, + input + .fhe_inputs + .ciphertexts + .iter() + .map(|(_, index)| *index) + .collect(), + input.published.clone(), + crisp(), + ) + .unwrap(); + for (bytes, _) in &input.fhe_inputs.ciphertexts { + process.absorb(bytes).unwrap(); + } + let selected = process.select().unwrap(); + assert_eq!(selected.indices(), held_selection.as_slice()); + let (streamed, streamed_tally) = selected + .finish(fhe_processor, |index| { + Ok(input.fhe_inputs.ciphertexts[index].0.clone()) + }) + .unwrap(); + + assert_eq!(streamed.merkle_root, held.merkle_root); + assert_eq!(streamed.ciphertext_hash, held.ciphertext_hash); + assert_eq!(streamed.ciphertext_commitment, held.ciphertext_commitment); + assert_eq!(streamed.params_hash, held.params_hash); + assert_eq!(streamed_tally, held_tally); + assert_eq!(round.decrypt_tally(&streamed_tally, 2), vec![6, 7]); +} diff --git a/examples/CRISP/program/tests/selection.rs b/examples/CRISP/program/tests/selection.rs index 5826020531..8af4717843 100644 --- a/examples/CRISP/program/tests/selection.rs +++ b/examples/CRISP/program/tests/selection.rs @@ -10,7 +10,7 @@ //! problem — an append-only tree that anyone may write to. A program where every input counts wants //! the crate's default instead. -use e3_compute_provider::policy::PublishedInput; +use e3_compute_provider::policy::InputRecord; use e3_user_program::policy::chain_head_per_slot; /// One published entry, as a test states it. @@ -60,14 +60,13 @@ fn metadata(entry: &Entry) -> Vec { fn select(entries: &[Entry]) -> Vec { let stored: Vec<[u8; 32]> = (0..entries.len()).map(|i| [i as u8; 32]).collect(); let metadatas: Vec> = entries.iter().map(metadata).collect(); - let bytes = vec![0u8]; - let inputs: Vec = entries + let inputs: Vec = entries .iter() .enumerate() - .map(|(index, entry)| PublishedInput { + .map(|(index, entry)| InputRecord { index, - ciphertext: &bytes, + ciphertext_hash: [0; 32], commitment: Some(&stored[index]), metadata: &metadatas[index], recomputed: Some(if entry.usable { @@ -207,12 +206,11 @@ fn interleaved_slots_resolve_independently() { #[test] fn an_entry_without_valid_metadata_is_not_selected() { let stored = [7u8; 32]; - let bytes = vec![0u8]; let malformed = [0u8; 4]; - let inputs = vec![PublishedInput { + let inputs = vec![InputRecord { index: 0, - ciphertext: &bytes, + ciphertext_hash: [0; 32], commitment: Some(&stored), metadata: &malformed, recomputed: Some(stored), diff --git a/examples/CRISP/server/src/server/repo.rs b/examples/CRISP/server/src/server/repo.rs index 7d1976436e..54a5ea8965 100644 --- a/examples/CRISP/server/src/server/repo.rs +++ b/examples/CRISP/server/src/server/repo.rs @@ -13,7 +13,7 @@ use super::{ models::{CurrentRound, E3Crisp, E3StateLite, WebResultRequest}, }; use alloy::primitives::keccak256; -use e3_compute_provider::policy::PublishedInput; +use e3_compute_provider::policy::InputRecord; use e3_sdk::indexer::{models::E3 as InterfoldE3, DataStore, E3Repository, SharedStore}; use e3_user_program::policy::chain_head_per_slot; use eyre::Result; @@ -159,12 +159,12 @@ impl InputSnapshot { bytes }) .collect(); - let inputs: Vec = entries + let inputs: Vec = entries .iter() .zip(&metadata) - .map(|(&position, metadata)| PublishedInput { + .map(|(&position, metadata)| InputRecord { index: self.ciphertexts[position].1 as usize, - ciphertext: &[], + ciphertext_hash: [0; 32], commitment: Some(&commitment), metadata, recomputed: self.usable[position].then_some(commitment), diff --git a/packages/interfold-contracts/scripts/openVm.ts b/packages/interfold-contracts/scripts/openVm.ts index 9101063b97..2d100c3404 100644 --- a/packages/interfold-contracts/scripts/openVm.ts +++ b/packages/interfold-contracts/scripts/openVm.ts @@ -5,7 +5,49 @@ // or FITNESS FOR A PARTICULAR PURPOSE. import type { HardhatEthers } from "@nomicfoundation/hardhat-ethers/types"; import { createHash } from "node:crypto"; -import { readFileSync, statSync } from "node:fs"; +import { existsSync, readFileSync, statSync } from "node:fs"; +import path from "node:path"; + +const OPENVM_IDENTITY_SETTINGS = [ + "OPENVM_APP_EXE_COMMIT", + "OPENVM_APP_VM_COMMIT", + "OPENVM_VERIFIER_ARTIFACT", + "OPENVM_VERIFIER_SHA256", + "OPENVM_HALO2_VERIFIER", + "OPENVM_HALO2_RUNTIME_CODE_HASH", +]; + +/** + * The environment `deployOpenVmReceiptVerifier` reads, filled from the worker configuration that + * `interfold program compile` wrote for the project in `projectDir`. That binds the deployed + * verifier to the guest the project's service proves. Nothing is read when any OpenVM identity + * setting is already in `environment`, so an explicit identity is never mixed with a compiled one. + */ +export function compiledOpenVmEnvironment( + projectDir: string, + environment: Record = process.env, +): Record { + if (OPENVM_IDENTITY_SETTINGS.some((name) => environment[name])) { + return environment; + } + const configPath = path.join( + projectDir, + ".interfold", + "caches", + "openvm", + "prover.json", + ); + if (!existsSync(configPath)) return environment; + const config = JSON.parse(readFileSync(configPath, "utf8")); + console.log(`Using the OpenVM receipt identity in ${configPath}`); + return { + ...environment, + OPENVM_APP_EXE_COMMIT: config.app_commit?.app_exe_commit, + OPENVM_APP_VM_COMMIT: config.app_commit?.app_vm_commit, + OPENVM_VERIFIER_ARTIFACT: config.verifier_artifact, + OPENVM_VERIFIER_SHA256: config.verifier_sha256, + }; +} /** Deploy a receipt binding from explicit application commitments and a checked Halo2 verifier. */ export async function deployOpenVmReceiptVerifier( diff --git a/scripts/generate-provenance-manifest.ts b/scripts/generate-provenance-manifest.ts index 7f0217d90e..c3db864315 100644 --- a/scripts/generate-provenance-manifest.ts +++ b/scripts/generate-provenance-manifest.ts @@ -64,11 +64,11 @@ async function main() { const unresolved: string[] = [] const files = [ 'Cargo.lock', - 'crates/support/Cargo.lock', - 'crates/support/openvm/guest/Cargo.lock', - 'crates/support/openvm/prover/Cargo.lock', + 'examples/CRISP/Cargo.lock', + 'examples/CRISP/guest/Cargo.lock', + 'crates/openvm-prover/Cargo.lock', 'rust-toolchain.toml', - 'crates/support/openvm/guest/openvm.toml', + 'examples/CRISP/guest/openvm.toml', ] const sourceDigests = Object.fromEntries(await Promise.all(files.map(async (file) => [file, await digest(path.join(root, file))]))) const sourceCommit = command('git', ['rev-parse', 'HEAD']) diff --git a/scripts/run-openvm.sh b/scripts/run-openvm.sh index 302709084f..85a713f13f 100644 --- a/scripts/run-openvm.sh +++ b/scripts/run-openvm.sh @@ -1,7 +1,11 @@ #!/usr/bin/env bash # SPDX-License-Identifier: LGPL-3.0-only +# +# OpenVM tasks for this repository. The CRISP tasks run in examples/CRISP; a project made with +# `interfold init` uses `interfold program compile` and `interfold program start` instead. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CRISP="$ROOT/examples/CRISP" command="${1:-}" shift || true case "$command" in @@ -10,35 +14,42 @@ case "$command" in ;; fixture) export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/crisp-server}" - exec cargo run --locked --release --manifest-path "$ROOT/examples/CRISP/Cargo.toml" -p e3-user-program --example openvm_fixture -- "$@" + exec cargo run --locked --release --manifest-path "$CRISP/Cargo.toml" -p e3-user-program --example openvm_fixture -- "$@" ;; crisp-server-build|crisp-server-test) export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/crisp-server}" - exec cargo "${command#crisp-server-}" --locked --manifest-path "$ROOT/examples/CRISP/Cargo.toml" -p crisp "$@" + exec cargo "${command#crisp-server-}" --locked --manifest-path "$CRISP/Cargo.toml" -p crisp "$@" ;; - service-build|service-test|service-check) - export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/service}" - exec cargo "${command#service-}" --locked --manifest-path "$ROOT/crates/support/Cargo.toml" "$@" + # CRISP's proving service: examples/CRISP/.interfold/support/openvm/service. + service-build|service-check) + exec cargo "${command#service-}" --locked --manifest-path "$CRISP/Cargo.toml" -p e3-support-scripts-openvm "$@" + ;; + service-test) + exec cargo test --locked --manifest-path "$ROOT/Cargo.toml" -p e3-openvm-types -p e3-openvm-host -p e3-compute-provider -p e3-program-server "$@" + ;; + # Builds CRISP's guest, keys, receipt identity, worker configuration and service. Takes the same + # OPENVM_* environment as `interfold program compile`. + compile) + cd "$CRISP" + exec bash .interfold/support/openvm/compile "$@" ;; service-start) - : "${OPENVM_PROVER_BIN:?Set OPENVM_PROVER_BIN}" - : "${OPENVM_PROVER_CONFIG:?Set OPENVM_PROVER_CONFIG}" - export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/service}" - exec cargo run --locked --release --manifest-path "$ROOT/crates/support/Cargo.toml" -p e3-support-app -- "$@" + cd "$CRISP" + exec bash .interfold/support/openvm/start "$@" ;; prover-build|prover-test|prover-check) export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/prover}" - exec cargo "${command#prover-}" --locked --release --manifest-path "$ROOT/crates/support/openvm/prover/Cargo.toml" "$@" + exec cargo "${command#prover-}" --locked --release --manifest-path "$ROOT/crates/openvm-prover/Cargo.toml" "$@" ;; prover) export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target/openvm/prover}" - exec cargo run --locked --release --manifest-path "$ROOT/crates/support/openvm/prover/Cargo.toml" -- "$@" + exec cargo run --locked --release --manifest-path "$ROOT/crates/openvm-prover/Cargo.toml" -- "$@" ;; + # `cargo openvm ` in CRISP's guest, with the guest's configuration flags. guest) - export CARGO_TARGET_DIR="$ROOT/target/openvm/guest" export RUSTFLAGS="${RUSTFLAGS:-} --cfg crisp_openvm --cfg crisp_fhe_optimized" export OPENVM_BUILD_LOCKED=1 - cd "$ROOT/crates/support/openvm/guest" + cd "$CRISP/guest" exec cargo openvm "$@" ;; contract-test) @@ -50,5 +61,5 @@ case "$command" in service-e2e) OPENVM_E2E_ENABLED=1 exec pnpm --filter @crisp-e3/contracts test --network localhost tests/openvm-service.test.ts "$@" ;; - *) echo 'Usage: pnpm openvm cli-build|fixture|crisp-server-build|crisp-server-test|service-build|service-test|service-check|service-start|prover-build|prover-test|prover-check|prover|guest|contract-test|proof-test|service-e2e [arguments]' >&2; exit 2 ;; + *) echo 'Usage: pnpm openvm cli-build|fixture|crisp-server-build|crisp-server-test|service-build|service-check|service-test|compile|service-start|prover-build|prover-test|prover-check|prover|guest|contract-test|proof-test|service-e2e [arguments]' >&2; exit 2 ;; esac diff --git a/templates/default/.gitignore b/templates/default/.gitignore index ce297d7abc..6146a941b6 100644 --- a/templates/default/.gitignore +++ b/templates/default/.gitignore @@ -19,6 +19,7 @@ node_modules .interfold/noir/ /target +/guest/target .interfold/generated/ diff --git a/templates/default/.gitignore.bak b/templates/default/.gitignore.bak index f58beb4747..0d59bc6080 100644 --- a/templates/default/.gitignore.bak +++ b/templates/default/.gitignore.bak @@ -14,6 +14,7 @@ node_modules /typechain-types /target +/guest/target # solidity-coverage files /coverage diff --git a/templates/default/.interfold/support/openvm b/templates/default/.interfold/support/openvm new file mode 120000 index 0000000000..c63cdf9dbf --- /dev/null +++ b/templates/default/.interfold/support/openvm @@ -0,0 +1 @@ +../../../../crates/support-scripts/openvm \ No newline at end of file diff --git a/templates/default/Cargo.lock b/templates/default/Cargo.lock index 6456f62fd7..22eac3b459 100644 --- a/templates/default/Cargo.lock +++ b/templates/default/Cargo.lock @@ -1310,6 +1310,8 @@ dependencies = [ "light-poseidon", "num-bigint 0.4.6", "num-traits", + "openvm-keccak256", + "rayon", "serde", "sha2", "sha3 0.10.8", @@ -1334,6 +1336,26 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "e3-openvm-host" +version = "0.19.0-test.2" +dependencies = [ + "anyhow", + "e3-compute-provider", + "e3-openvm-types", + "tempfile", + "tokio", +] + +[[package]] +name = "e3-openvm-types" +version = "0.19.0-test.2" +dependencies = [ + "bincode", + "e3-compute-provider", + "serde", +] + [[package]] name = "e3-parity-matrix" version = "0.19.0-test.2" @@ -1395,6 +1417,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "e3-support-scripts-openvm" +version = "0.1.0" +dependencies = [ + "anyhow", + "e3-openvm-host", + "e3-program-server", + "e3-user-program", + "tokio", +] + [[package]] name = "e3-user-program" version = "0.1.0" @@ -2719,6 +2752,52 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "openvm-custom-insn" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openvm-keccak256" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-keccak256-guest", + "spin", + "tiny-keccak", +] + +[[package]] +name = "openvm-keccak256-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-platform", +] + +[[package]] +name = "openvm-platform" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "openvm-rv32im-guest", +] + +[[package]] +name = "openvm-rv32im-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "openvm-custom-insn", + "strum_macros", +] + [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -3714,6 +3793,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" + [[package]] name = "spki" version = "0.7.3" @@ -3742,6 +3827,19 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[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.117", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3855,15 +3953,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.27.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/templates/default/Cargo.toml b/templates/default/Cargo.toml index 16a0280ddf..68bab4f4c6 100644 --- a/templates/default/Cargo.toml +++ b/templates/default/Cargo.toml @@ -2,7 +2,8 @@ resolver = "3" members = [ "program", - ".interfold/support/dev" + ".interfold/support/dev", + ".interfold/support/openvm/service" ] [workspace.dependencies] @@ -13,5 +14,6 @@ e3-program-server = { path = "../../crates/program-server" } e3-bfv-client = { path = "../../crates/bfv-client" } e3-fhe-params = { path = "../../crates/fhe-params" } e3-compute-provider = { path = "../../crates/compute-provider" } +e3-openvm-host = { path = "../../crates/openvm-host" } rand = "0.9" anyhow = "1.0.86" diff --git a/templates/default/README.md b/templates/default/README.md index 603a99d0e7..583c190160 100644 --- a/templates/default/README.md +++ b/templates/default/README.md @@ -23,14 +23,21 @@ As system requirements: ### Configure OpenVM -The program server uses OpenVM. Build a guest for your program policy, prepare its proving keys, -and configure `program.openvm` in `interfold.config.yaml`. See the repository's -[`crates/support/openvm/README.md`](../../crates/support/openvm/README.md) for worker setup and -verifier deployment. The reference CRISP guest cannot prove an unrelated template policy. - -Contract deployment requires both application commitments and either a checksummed Halo2 verifier -artifact or an existing verifier address with its expected runtime code hash. Missing settings stop -deployment; they do not select a mock verifier. +Real proofs use OpenVM. `guest/` proves your `program/`, with your processor and your input +policy, and `.interfold/support/openvm` is the proving service. Build the OpenVM workers, set +`program.openvm` in `interfold.config.yaml`, then run: + +```sh +interfold program compile # the guest, its keys and receipt identity, and the service +``` + +A machine with a working CUDA GPU proves on it when `prover_bin_cuda` is set; any other machine +proves on the CPU. See the OpenVM guide in the Interfold repository +(`crates/openvm-prover/README.md`) for the workers and the Halo2 artifacts. + +Contract deployment reads the receipt identity and verifier artifact that `compile` wrote, unless +`OPENVM_*` settings name another. Without either, deployment stops; it does not select a mock +verifier. ### Install Metamask diff --git a/templates/default/deploy/default.ts b/templates/default/deploy/default.ts index 9805ee0186..690f0e7db8 100644 --- a/templates/default/deploy/default.ts +++ b/templates/default/deploy/default.ts @@ -5,6 +5,7 @@ // or FITNESS FOR A PARTICULAR PURPOSE. import { + compiledOpenVmEnvironment, deployOpenVmReceiptVerifier, getDeploymentChain, readDeploymentArgs, @@ -12,7 +13,7 @@ import { updateE3Config, } from '@interfold/contracts/scripts' import { Interfold__factory as InterfoldFactory } from '@interfold/contracts/types' -import { ensureTemplateCwd, INTERFOLD_CONFIG_FILE } from '../scripts/template-paths' +import { ensureTemplateCwd, INTERFOLD_CONFIG_FILE, TEMPLATE_ROOT } from '../scripts/template-paths' import { MyProgram__factory as MyProgramFactory } from '../types/factories/contracts' import hre from 'hardhat' @@ -53,7 +54,8 @@ export const deployTemplate = async () => { if (unprovedTest) { verifier = await ethers.deployContract('MockOpenVmReceiptVerifier') } else { - const deployed = await deployOpenVmReceiptVerifier(ethers) + // The identity `interfold program compile` wrote, unless OPENVM_* settings name one. + const deployed = await deployOpenVmReceiptVerifier(ethers, compiledOpenVmEnvironment(TEMPLATE_ROOT)) verifier = deployed.receipt verifierConstructorArgs = { verifier: deployed.halo2Verifier, appExeCommit: deployed.appExeCommit, appVmCommit: deployed.appVmCommit } } diff --git a/crates/support/Cargo.lock b/templates/default/guest/Cargo.lock similarity index 61% rename from crates/support/Cargo.lock rename to templates/default/guest/Cargo.lock index 16aae07937..20130f6284 100644 --- a/crates/support/Cargo.lock +++ b/templates/default/guest/Cargo.lock @@ -2,204 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "actix-codec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-http" -version = "3.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "base64", - "bitflags", - "brotli", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "flate2", - "foldhash 0.1.5", - "futures-core", - "h2 0.3.27", - "http 0.2.12", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand 0.9.5", - "sha1", - "smallvec", - "tokio", - "tokio-util", - "tracing", - "zstd", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn 2.0.119", -] - -[[package]] -name = "actix-router" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" -dependencies = [ - "bytestring", - "cfg-if", - "http 0.2.12", - "regex", - "regex-lite", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.10", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "bytes", - "bytestring", - "cfg-if", - "cookie", - "derive_more", - "encoding_rs", - "foldhash 0.1.5", - "futures-core", - "futures-util", - "impl-more", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "regex-lite", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.5.10", - "time", - "tracing", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "ahash" version = "0.8.12" @@ -214,28 +16,13 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -255,7 +42,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -283,7 +70,7 @@ dependencies = [ "derive_more", "foldhash 0.2.0", "hashbrown 0.16.1", - "indexmap", + "indexmap 2.14.2", "itoa", "k256", "keccak-asm", @@ -293,15 +80,15 @@ dependencies = [ "ruint", "rustc-hash", "serde", - "sha3", + "sha3 0.10.8", "tiny-keccak", ] [[package]] name = "alloy-rlp" -version = "0.3.12" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" dependencies = [ "arrayvec", "bytes", @@ -309,13 +96,13 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" +checksum = "60dd79f578c3912f1fc2a150dbeb8110b8cfb976c60f98ebf6de9d5da5965a2b" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error2", + "proc-macro-error3", "proc-macro2", "quote", "syn 2.0.119", @@ -323,27 +110,27 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" +checksum = "9edb8520f2f94275e1caa73c85207dcc78ec402a9a4c429240f9a0783a8f16c0" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap", - "proc-macro-error2", + "indexmap 2.14.2", + "proc-macro-error3", "proc-macro2", "quote", + "sha3 0.11.0", "syn 2.0.119", "syn-solidity", - "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" +checksum = "66af2d9344882172993be5f5cbfd349fdfa52cb548f7af8715b446fb35ef6001" dependencies = [ "const-hex", "dunce", @@ -362,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -378,18 +165,12 @@ dependencies = [ ] [[package]] -name = "anstream" -version = "0.6.21" +name = "android_system_properties" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ - "anstyle", - "anstyle-parse 0.2.7", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", + "libc", ] [[package]] @@ -399,7 +180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", - "anstyle-parse 1.0.0", + "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -409,18 +190,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" @@ -437,7 +209,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -448,7 +220,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -575,6 +347,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af" +dependencies = [ + "ark-ff-asm 0.6.0", + "ark-ff-macros 0.6.0", + "ark-serialize 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "educe", + "num-bigint 0.4.6", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -605,6 +394,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "ark-ff-asm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -643,6 +442,19 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "ark-ff-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -706,6 +518,19 @@ dependencies = [ "num-bigint 0.4.6", ] +[[package]] +name = "ark-serialize" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b" +dependencies = [ + "ark-serialize-derive 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "num-bigint 0.4.6", + "serde_with", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -728,6 +553,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "ark-serialize-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -735,7 +571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.8", ] [[package]] @@ -745,7 +581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.8", ] [[package]] @@ -755,20 +591,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.8", ] [[package]] -name = "arrayvec" -version = "0.7.6" +name = "ark-std" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155" +dependencies = [ + "num-traits", + "rand 0.8.8", +] [[package]] -name = "atomic-waker" -version = "1.1.2" +name = "arrayvec" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "auto_impl" @@ -783,24 +623,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "backtrace" -version = "0.3.76" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base16ct" @@ -816,9 +641,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bincode" @@ -846,15 +671,21 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.10.0" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -872,31 +703,28 @@ dependencies = [ ] [[package]] -name = "brotli" -version = "8.0.2" +name = "block-buffer" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", + "hybrid-array", ] [[package]] -name = "brotli-decompressor" -version = "5.0.0" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "tinyvec", ] [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byte-slice-cast" @@ -906,9 +734,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -918,39 +746,40 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] -[[package]] -name = "bytestring" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" -dependencies = [ - "bytes", -] - [[package]] name = "cc" -version = "1.2.47" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "chrono" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] [[package]] name = "clap" @@ -968,7 +797,7 @@ version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "anstream 1.0.0", + "anstream", "anstyle", "clap_lex", "strsim", @@ -988,24 +817,30 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "const-default" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" [[package]] name = "const-hex" -version = "1.17.0" +version = "1.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +checksum = "0e59eef12462b0f9b0a3620219be5d639afd79fe39dff0a42c3997061f9298b4" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -1018,11 +853,12 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" dependencies = [ "const_format_proc_macros", + "konst", ] [[package]] @@ -1037,24 +873,12 @@ dependencies = [ ] [[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" +name = "convert_case" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ - "core-foundation-sys", - "libc", + "unicode-segmentation", ] [[package]] @@ -1073,19 +897,25 @@ dependencies = [ ] [[package]] -name = "crc32fast" -version = "1.5.0" +name = "cpufeatures" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ - "cfg-if", + "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1093,18 +923,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -1126,14 +956,54 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + [[package]] name = "der" version = "0.7.10" @@ -1146,11 +1016,11 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", + "serde_core", ] [[package]] @@ -1166,21 +1036,23 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version 0.4.1", "syn 2.0.119", "unicode-xid", ] @@ -1200,21 +1072,20 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", - "crypto-common", + "crypto-common 0.1.7", "subtle", ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "digest" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "block-buffer 0.12.1", + "crypto-common 0.2.2", ] [[package]] @@ -1229,6 +1100,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "e3-bfv-client" version = "0.19.0-test.2" @@ -1260,7 +1137,7 @@ dependencies = [ "openvm-keccak256", "serde", "sha2", - "sha3", + "sha3 0.10.8", "thiserror 1.0.69", "zk-kit-imt", ] @@ -1282,6 +1159,29 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "e3-openvm-guest" +version = "0.1.0" +dependencies = [ + "e3-compute-provider", + "e3-openvm-types", + "e3-safe", + "e3-user-program", + "openvm", + "openvm-algebra-guest", + "openvm-sha2", + "sha2", +] + +[[package]] +name = "e3-openvm-types" +version = "0.19.0-test.2" +dependencies = [ + "bincode", + "e3-compute-provider", + "serde", +] + [[package]] name = "e3-parity-matrix" version = "0.19.0-test.2" @@ -1310,57 +1210,12 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "hex", - "sha3", - "taceo-poseidon2", -] - -[[package]] -name = "e3-support-app" -version = "0.1.0" -dependencies = [ - "actix-web", - "anyhow", - "e3-compute-provider", - "e3-support-host", - "e3-support-types", - "env_logger", - "hex", - "reqwest", - "serde", - "serde_json", - "tokio", -] - -[[package]] -name = "e3-support-host" -version = "0.1.0" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "anyhow", - "bincode", - "e3-compute-provider", - "e3-support-types", - "e3-user-program", - "hex", - "serde", - "serde_json", - "sha2", - "tempfile", - "tokio", -] - -[[package]] -name = "e3-support-types" -version = "0.1.0" -dependencies = [ - "alloy-primitives", - "anyhow", - "derivative", - "e3-compute-provider", - "hex", + "num-bigint 0.4.6", + "openvm", + "openvm-algebra-guest", "serde", - "serde_json", + "sha3 0.10.8", + "taceo-poseidon2", ] [[package]] @@ -1371,10 +1226,6 @@ dependencies = [ "e3-fhe-params", "fhe", "fhe-traits", - "openvm-keccak256", - "openvm-sha2", - "sha2", - "sha3", ] [[package]] @@ -1434,9 +1285,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "elliptic-curve" @@ -1458,55 +1309,35 @@ dependencies = [ ] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "embedded-alloc" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" dependencies = [ - "cfg-if", + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", ] [[package]] name = "enum-ordinalize" -version = "4.3.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", -] - -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream 0.6.21", - "anstyle", - "env_filter", - "jiff", - "log", + "syn 3.0.6", ] [[package]] @@ -1522,7 +1353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1533,9 +1364,9 @@ checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fastrlp" @@ -1590,7 +1421,7 @@ dependencies = [ "rand_distr", "rayon", "serde", - "thiserror 2.0.21", + "thiserror 2.0.20", "zeroize", "zeroize_derive", ] @@ -1615,7 +1446,7 @@ dependencies = [ "rand_chacha 0.9.0", "serde", "sha2", - "thiserror 2.0.21", + "thiserror 2.0.20", "zeroize", ] @@ -1642,9 +1473,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" [[package]] name = "fixed-hash" @@ -1653,7 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.6", + "rand 0.8.8", "rustc-hex", "static_assertions", ] @@ -1664,16 +1495,6 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" -[[package]] -name = "flate2" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1692,80 +1513,41 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -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-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-core", "futures-task", "pin-project-lite", - "pin-utils", + "slab", ] [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1774,9 +1556,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", @@ -1791,15 +1573,20 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "getrandom" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] [[package]] name = "group" @@ -1813,42 +1600,10 @@ dependencies = [ ] [[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.12" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.4.0", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" @@ -1881,6 +1636,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "heck" version = "0.5.0" @@ -1903,330 +1664,103 @@ dependencies = [ ] [[package]] -name = "http" -version = "0.2.12" +name = "hybrid-array" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" dependencies = [ - "bytes", - "fnv", - "itoa", + "typenum", ] [[package]] -name = "http" -version = "1.4.0" +name = "iana-time-zone" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ - "bytes", - "itoa", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "bytes", - "http 1.4.0", + "cc", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "impl-codec" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "bytes", - "futures-core", - "http 1.4.0", - "http-body", - "pin-project-lite", + "parity-scale-codec", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "impl-trait-for-tuples" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] -name = "httpdate" -version = "1.0.3" +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] [[package]] -name = "hyper" -version = "1.8.1" +name = "indexmap" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2 0.4.12", - "http 1.4.0", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", ] [[package]] -name = "hyper-rustls" -version = "0.27.7" +name = "is_terminal_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http 1.4.0", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] -name = "hyper-tls" -version = "0.6.0" +name = "itertools" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "either", ] [[package]] -name = "hyper-util" -version = "0.1.18" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.4.0", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.1", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[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-more" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "indexmap" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - -[[package]] -name = "io-uring" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[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.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", + "either", ] [[package]] @@ -2249,51 +1783,72 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.16" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" dependencies = [ + "defmt", + "jiff-core", "jiff-static", + "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", ] [[package]] name = "jiff-static" -version = "0.2.16" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" dependencies = [ + "jiff-core", "proc-macro2", "quote", "syn 2.0.119", ] [[package]] -name = "jobserver" -version = "0.1.34" +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ - "getrandom 0.3.4", - "libc", + "jiff-tzdb", ] [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -2312,28 +1867,47 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", ] [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee" dependencies = [ "digest 0.10.7", "sha3-asm", ] [[package]] -name = "language-tags" -version = "0.3.2" +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" [[package]] name = "lean-imt" @@ -2346,15 +1920,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "light-poseidon" @@ -2369,54 +1943,37 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.11.0" +name = "linked_list_allocator" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897" [[package]] -name = "litemap" -version = "0.8.1" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] -name = "local-channel" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" -dependencies = [ - "futures-core", - "futures-sink", - "local-waker", -] - -[[package]] -name = "local-waker" -version = "0.1.4" +name = "log" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] -name = "lock_api" -version = "0.4.14" +name = "lru" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "scopeguard", + "hashbrown 0.15.5", ] -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - [[package]] name = "macro-string" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" dependencies = [ "proc-macro2", "quote", @@ -2425,9 +1982,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" dependencies = [ "autocfg", "rawpointer", @@ -2435,37 +1992,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.61.2", -] +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "multimap" @@ -2473,23 +2002,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndarray" version = "0.17.2" @@ -2528,6 +2040,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.8", ] [[package]] @@ -2539,7 +2052,7 @@ dependencies = [ "num-integer", "num-traits", "rand 0.9.5", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -2571,30 +2084,56 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" dependencies = [ - "autocfg", "num-integer", "num-traits", ] +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-prime" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e238432a7881ec7164503ccc516c014bf009be7984cde1ba56837862543bdec3" +dependencies = [ + "bitvec", + "either", + "lru", + "num-bigint 0.4.6", + "num-integer", + "num-modular", + "num-traits", + "rand 0.8.8", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2616,20 +2155,11 @@ dependencies = [ "libm", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -2638,47 +2168,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "openssl" -version = "0.10.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +name = "openvm" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", + "bytemuck", + "getrandom 0.2.17", + "getrandom 0.3.4", + "num-bigint 0.4.6", + "openvm-custom-insn", + "openvm-platform", + "openvm-rv32im-guest", + "serde", ] [[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +name = "openvm-algebra-complex-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "proc-macro2", + "openvm-macros-common", "quote", "syn 2.0.119", ] [[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +name = "openvm-algebra-guest" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "num-bigint 0.4.6", + "once_cell", + "openvm-algebra-complex-macros", + "openvm-algebra-moduli-macros", + "openvm-custom-insn", + "openvm-rv32im-guest", + "serde-big-array", + "strum_macros", +] [[package]] -name = "openssl-sys" -version = "0.9.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +name = "openvm-algebra-moduli-macros" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "num-bigint 0.4.6", + "num-prime", + "openvm-macros-common", + "quote", + "syn 2.0.119", ] [[package]] @@ -2709,11 +2247,22 @@ dependencies = [ "openvm-platform", ] +[[package]] +name = "openvm-macros-common" +version = "2.0.2" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" +dependencies = [ + "syn 2.0.119", +] + [[package]] name = "openvm-platform" version = "2.0.2" source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.2#59a69b8b0cbee7011ac978e4cc07707ee3681944" dependencies = [ + "critical-section", + "embedded-alloc", + "libm", "openvm-custom-insn", "openvm-rv32im-guest", ] @@ -2772,46 +2321,17 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pest" -version = "2.8.4" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" dependencies = [ "memchr", "ucd-trie", @@ -2825,20 +2345,14 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.2", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs8" @@ -2850,36 +2364,21 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" dependencies = [ "portable-atomic", ] -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -2913,7 +2412,7 @@ checksum = "bb24cb4f70d64221509ab3dca82ad2ec24e1d7f3fa3e7cb9eed4ced578683287" dependencies = [ "itertools 0.10.5", "num", - "rand 0.8.6", + "rand 0.8.8", ] [[package]] @@ -2929,30 +2428,30 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.7", + "toml_edit 0.25.15+spec-1.1.0", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "proc-macro-error-attr3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "82366fd7d8b7a440d66d13418820c69df9b3908bcb1a0476d7f5ce5d12f5a04d" dependencies = [ "proc-macro2", "quote", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "b511283ea8a74b4b39447b128c5d00f03a356b7424554b13e298a5550100d9ac" dependencies = [ - "proc-macro-error-attr2", + "proc-macro-error-attr3", "proc-macro2", "quote", "syn 2.0.119", @@ -2969,13 +2468,13 @@ dependencies = [ [[package]] name = "proptest" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", - "bitflags", + "bitflags 2.13.2", "num-traits", "rand 0.9.5", "rand_chacha 0.9.0", @@ -3081,6 +2580,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -3089,9 +2594,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -3105,7 +2610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -3126,7 +2631,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3135,14 +2640,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", "serde", @@ -3164,7 +2669,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3173,7 +2678,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags", + "bitflags 2.13.2", ] [[package]] @@ -3209,19 +2714,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ - "bitflags", + "proc-macro2", + "quote", + "syn 3.0.6", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3231,66 +2747,20 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" - [[package]] name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "reqwest" -version = "0.12.22" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "h2 0.4.12", - "http 1.4.0", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rfc6979" @@ -3302,20 +2772,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rlp" version = "0.5.2" @@ -3326,16 +2782,29 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlsf" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07393724337be2ee43a9d86164df4505746874a3fa65913374bc6d6a92314362" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "rustversion", +] + [[package]] name = "ruint" -version = "1.17.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "2973657b5127d510e230f5c63d2d106af9c8f79393d8b9f4647323e8196bdde5" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "ark-ff 0.5.0", + "ark-ff 0.6.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -3345,7 +2814,7 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.6", + "rand 0.8.8", "rand 0.9.5", "rlp", "ruint-macro", @@ -3360,17 +2829,11 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc-hex" @@ -3393,60 +2856,27 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.27", + "semver 1.0.28", ] [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ - "bitflags", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", + "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" @@ -3462,24 +2892,33 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] -name = "schannel" -version = "0.1.28" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" dependencies = [ - "windows-sys 0.61.2", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "schemars" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] [[package]] name = "sec1" @@ -3495,29 +2934,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.11.0" @@ -3529,9 +2945,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "semver-parser" @@ -3552,6 +2968,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -3595,26 +3020,23 @@ dependencies = [ ] [[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 = "sha1" -version = "0.10.6" +name = "serde_with" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "base64", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "time", ] [[package]] @@ -3624,7 +3046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -3635,14 +3057,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", - "keccak", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.2", ] [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331" dependencies = [ "cc", "cfg-if", @@ -3650,18 +3082,9 @@ dependencies = [ [[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.7" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" -dependencies = [ - "libc", -] +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signature" @@ -3673,43 +3096,17 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.1" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "spin" @@ -3727,12 +3124,6 @@ dependencies = [ "der", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - [[package]] name = "static_assertions" version = "1.1.0" @@ -3799,9 +3190,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.4.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" +checksum = "eb6a2e3c7f7a3e4e83d1752cec5d1e357ced0cf96e85419b6a07f227db3def3a" dependencies = [ "paste", "proc-macro2", @@ -3809,47 +3200,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "taceo-poseidon2" version = "0.2.1" @@ -3871,15 +3221,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -3893,11 +3243,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.21" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.21", + "thiserror-impl 2.0.20", ] [[package]] @@ -3913,9 +3263,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.21" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", @@ -3924,30 +3274,29 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -3959,82 +3308,14 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ - "crunchy", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "slab", - "socket2 0.5.10", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", + "crunchy", ] [[package]] -name = "tokio-util" -version = "0.7.17" +name = "tinyvec" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "toml" @@ -4059,9 +3340,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -4072,33 +3353,33 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.14.2", "serde", "serde_spanned", "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.15", ] [[package]] name = "toml_edit" -version = "0.23.7" +version = "0.25.15+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" dependencies = [ - "indexmap", - "toml_datetime 0.7.3", + "indexmap 2.14.2", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow", + "winnow 1.0.4", ] [[package]] @@ -4107,94 +3388,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http 1.4.0", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[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.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -4222,38 +3420,21 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "untrusted" -version = "0.9.0" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" [[package]] -name = "url" -version = "2.5.4" +name = "unicode-segmentation" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] -name = "utf8_iter" -version = "1.0.4" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "utf8parse" @@ -4267,12 +3448,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -4288,15 +3463,6 @@ dependencies = [ "libc", ] -[[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.1+wasi-snapshot-preview1" @@ -4305,18 +3471,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" dependencies = [ "cfg-if", "once_cell", @@ -4325,24 +3491,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4350,53 +3503,67 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.6", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.82" +name = "windows-core" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "js-sys", - "wasm-bindgen", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-link" -version = "0.2.1" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] -name = "windows-registry" -version = "0.6.1" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "proc-macro2", + "quote", + "syn 2.0.119", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-result" version = "0.4.1" @@ -4415,24 +3582,6 @@ dependencies = [ "windows-link", ] -[[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.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -4443,154 +3592,28 @@ dependencies = [ ] [[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 0.52.6", - "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-targets" -version = "0.53.5" +name = "winnow" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "memchr", ] -[[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_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[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_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[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_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[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_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[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_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "writeable" -version = "0.6.2" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "wyz" @@ -4601,75 +3624,31 @@ dependencies = [ "tap", ] -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - [[package]] name = "zerocopy" -version = "0.8.30" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" dependencies = [ "proc-macro2", "quote", "syn 2.0.119", - "synstructure", ] [[package]] name = "zeroize" -version = "1.9.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] @@ -4685,39 +3664,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "zk-kit-imt" version = "0.0.7" @@ -4727,31 +3673,3 @@ dependencies = [ "hex", "tiny-keccak", ] - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/templates/default/guest/Cargo.toml b/templates/default/guest/Cargo.toml new file mode 100644 index 0000000000..7e52d1c08c --- /dev/null +++ b/templates/default/guest/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "e3-openvm-guest" +version = "0.1.0" +edition = "2021" +license = "LGPL-3.0-only" + +# Proves this project's E3 program. Built for the OpenVM target with `cargo openvm build` +# (see `.interfold/support/openvm/compile`), so it is a workspace of its own. +[workspace] +resolver = "3" + +[dependencies] +openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2", features = ["std", "heap-embedded-alloc"] } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.2" } +e3-user-program = { path = "../program", features = ["openvm-hashes"] } +e3-compute-provider = { path = "../../../crates/compute-provider" } +e3-openvm-types = { path = "../../../crates/openvm-types" } +e3-safe = { path = "../../../crates/safe", features = ["openvm"] } +sha2 = "=0.10.9" + +[profile.release] +lto = "fat" +codegen-units = 1 diff --git a/templates/default/guest/openvm.toml b/templates/default/guest/openvm.toml new file mode 100644 index 0000000000..d22f7699cf --- /dev/null +++ b/templates/default/guest/openvm.toml @@ -0,0 +1,7 @@ +[app_vm_config.rv32i] +[app_vm_config.rv32m] +[app_vm_config.io] +[app_vm_config.sha2] +[app_vm_config.keccak] +[app_vm_config.modular] +supported_moduli = ["21888242871839275222246405745257275088548364400416034343698204186575808495617"] diff --git a/templates/default/guest/src/main.rs b/templates/default/guest/src/main.rs new file mode 100644 index 0000000000..6bfbd14d3b --- /dev/null +++ b/templates/default/guest/src/main.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. + +//! The OpenVM guest that proves this project's Secure Process. +//! +//! It reads the round one item at a time: a header, every ciphertext in index order, then the +//! ciphertexts the program's policy selected, again in index order. Only one ciphertext is held at +//! a time, so the round can be larger than the guest's memory. It reveals the SHA-256 digest of the +//! nine-word journal, which the receipt verifier recomputes on chain. + +openvm::init!(); + +use e3_compute_provider::SecureProcess; +use e3_openvm_types::{ComputeJournal, GuestHeader}; +use sha2::Digest; + +fn main() { + let header = GuestHeader::decode(&openvm::io::read_vec()).expect("Invalid guest header"); + let inputs = header.indices.len(); + let mut process = SecureProcess::new( + &header.params, + header.indices, + header.published, + e3_user_program::policy(), + ) + .expect("Invalid round"); + for _ in 0..inputs { + process + .absorb(&openvm::io::read_vec()) + .expect("Invalid input"); + } + let (result, _) = process + .select() + .expect("Input selection failed") + .finish(e3_user_program::fhe_processor, |_| { + Ok(openvm::io::read_vec()) + }) + .expect("Ciphertext aggregation failed"); + + let journal = ComputeJournal::new(&header.domain, &result) + .expect("Invalid compute journal") + .abi_bytes(); + let digest = openvm_sha2::Sha256::digest(&journal); + for (index, word) in digest.chunks_exact(4).enumerate() { + openvm::io::reveal_u32(u32::from_le_bytes(word.try_into().unwrap()), index); + } +} diff --git a/templates/default/interfold.config.yaml b/templates/default/interfold.config.yaml index dcc1c66904..869c4a1c1d 100644 --- a/templates/default/interfold.config.yaml +++ b/templates/default/interfold.config.yaml @@ -27,9 +27,13 @@ chains: deploy_block: 16 program: dev: false - # Configure program.openvm.repository, prover_bin, and prover_config with absolute paths. - # The worker must prove this program's policy, not the CRISP reference policy. - # See crates/support/openvm/README.md for the build and deployment requirements. + # Real proofs use program.openvm, with absolute paths local to the deployment: + # openvm: + # prover_bin: /path/to/interfold-openvm-prover # the CPU worker + # prover_bin_cuda: /path/to/interfold-openvm-prover-cuda # optional; used when a GPU works + # backend: auto # auto, cpu or cuda + # `interfold program compile` builds ./guest against ./program, and `interfold program start` + # serves real proofs. See the OpenVM worker README in the Interfold repository. # The scheduler defaults to 2 concurrent jobs and reserves 2 logical CPUs for Actix / libp2p. # It reduces concurrency when the host or cgroup memory limit is too small. # Example override on a dedicated 64 GB host: diff --git a/templates/default/program/Cargo.toml b/templates/default/program/Cargo.toml index 068a0ec483..3ad7541d18 100644 --- a/templates/default/program/Cargo.toml +++ b/templates/default/program/Cargo.toml @@ -3,6 +3,11 @@ name = "e3-user-program" version = "0.1.0" edition = "2024" +[features] +# Used by the OpenVM guest: computes Keccak-256 with OpenVM's instructions. Add any other hashes the +# program computes here too. +openvm-hashes = ["e3-compute-provider/openvm-hashes"] + [dependencies] fhe = { workspace = true } fhe-traits = { workspace = true } diff --git a/templates/default/program/src/lib.rs b/templates/default/program/src/lib.rs index c031336df5..ff994f2223 100644 --- a/templates/default/program/src/lib.rs +++ b/templates/default/program/src/lib.rs @@ -21,10 +21,13 @@ pub fn policy() -> InputPolicy { } /// Implementation of the CiphertextProcessor function -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +/// +/// The selected ciphertexts arrive one at a time, in index order. Inside the zkVM each is read and +/// checked only when the loop asks for it, so keep per-input state small. +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -37,7 +40,7 @@ mod tests { use anyhow::Result; use e3_compute_provider::FHEInputs; use e3_fhe_params::DEFAULT_BFV_PRESET; - use e3_fhe_params::{build_bfv_params_arc, encode_bfv_params, BfvParamSet}; + use e3_fhe_params::{BfvParamSet, build_bfv_params_arc, encode_bfv_params}; use fhe::bfv::{Encoding, Plaintext, PublicKey, SecretKey}; use fhe_traits::FheEncrypter; use fhe_traits::{DeserializeParametrized, FheDecrypter, Serialize}; @@ -78,8 +81,8 @@ mod tests { }; // Run the processor - let result = fhe_processor(&FHEProcessorInput { - ciphertexts: &fhe_inputs.ciphertexts, + let result = fhe_processor(FHEProcessorInput { + ciphertexts: &mut fhe_inputs.ciphertexts.into_iter(), params: ¶ms, }); From 6c8f7e30778b1f04206248b1e2082a34cf22bbb6 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 7 Oct 2026 17:31:11 +0500 Subject: [PATCH 06/20] fix: guest leaf hash, local template runs, and OpenVM docs - CRISP leaf: pass the ciphertext hash as a slice. The OpenVM guest's SHA-256 takes `&[u8]`, so the guest did not build. - Template: the local scripts run the development runner and the mock receipt verifier unless TEMPLATE_REAL_PROOFS=1, as CRISP's do with CRISP_REAL_PROOFS. Before, `pnpm dev:setup` and `pnpm dev:all` needed OpenVM artifacts. - compile: rely on cargo-openvm's own OPENVM_BUILD_LOCKED handling, which passed --locked twice, and default the segment memory to 8 GiB, which fits a 16 GB GPU. - Worker: `execute` runs the guest without proving and checks the revealed digest against the host's journal. The CRISP fixture can write an insecure round and the guest input for it. - Docs: compute provider, verification, configuration, CLI, template, CRISP setup, tutorials and learn pages describe OpenVM, per-project guests, streamed inputs and GPU or CPU workers. Live network facts keep their RISC Zero verifiers. --- agent/CRATES_ARCHITECTURE.md | 12 +- agent/flow-trace/04_DKG_AND_COMPUTATION.md | 28 +- agent/flow-trace/08_DATA_AVAILABILITY.md | 24 +- crates/compute-provider/Readme.md | 4 +- crates/openvm-prover/README.md | 90 +++--- crates/openvm-prover/src/main.rs | 37 ++- crates/support-scripts/openvm/compile | 7 +- docs/pages/CRISP/introduction.mdx | 12 +- docs/pages/CRISP/setup.mdx | 94 +++--- .../build/e3-program/complete-example.mdx | 22 +- .../build/e3-program/compute-provider.mdx | 293 ++++++++++-------- docs/pages/build/e3-program/index.mdx | 38 +-- .../build/e3-program/program-contract.mdx | 8 +- .../pages/build/e3-program/secure-process.mdx | 69 +++-- .../e3-program/verify-compute-provider.mdx | 147 +++++---- docs/pages/build/hello-world.mdx | 25 +- docs/pages/build/installation.mdx | 31 +- docs/pages/build/project-template.mdx | 120 +++---- docs/pages/build/quick-start.mdx | 25 +- docs/pages/build/sdk.mdx | 2 +- .../build/tutorials/deploy-to-testnet.mdx | 68 ++-- .../build/tutorials/write-e3-program.mdx | 49 +-- docs/pages/learn/architecture.mdx | 9 +- docs/pages/learn/cryptography.mdx | 2 +- docs/pages/learn/index.mdx | 2 +- docs/pages/learn/use-cases.mdx | 2 +- docs/pages/learn/what-is-e3.mdx | 2 +- docs/pages/reference/cli.mdx | 22 +- docs/pages/reference/configuration.mdx | 39 +-- docs/pages/reference/contracts.mdx | 33 +- docs/pages/reference/glossary.mdx | 12 +- examples/CRISP/Cargo.toml | 1 + examples/CRISP/program/Cargo.toml | 1 + .../CRISP/program/examples/openvm_fixture.rs | 111 +++++-- examples/CRISP/program/src/lib.rs | 2 +- templates/default/README.md | 27 +- templates/default/package.json | 2 +- templates/default/scripts/compile_program.sh | 12 + templates/default/scripts/lib/dev_config.sh | 13 +- 39 files changed, 829 insertions(+), 668 deletions(-) create mode 100755 templates/default/scripts/compile_program.sh diff --git a/agent/CRATES_ARCHITECTURE.md b/agent/CRATES_ARCHITECTURE.md index 943e17b3a8..7aad2ea220 100644 --- a/agent/CRATES_ARCHITECTURE.md +++ b/agent/CRATES_ARCHITECTURE.md @@ -1417,9 +1417,9 @@ commit. The normal `e3-support-scripts` backend uses `program.openvm`; it no lon Zero or Boundless. `program.dev` is an explicit, unproved runner. CRISP's encrypted-input and result-callback routes accept at most 4 MiB of JSON, to contain the -largest supported DA object after hexadecimal encoding. This limit is scoped to those routes; -read routes retain their smaller default limit. `CRISP_BIND_ADDR` selects the HTTP listener and -defaults to `0.0.0.0:4000`. -The server starts a multithread Tokio runtime. Input validation and large round-record updates must -not prevent the RPC transports from receiving WebSocket heartbeats. Actix HTTP workers retain their -own runtimes; the server does not use Actix actors or `actix_web::rt::spawn`. +largest supported DA object after hexadecimal encoding. This limit is scoped to those routes; read +routes retain their smaller default limit. `CRISP_BIND_ADDR` selects the HTTP listener and defaults +to `0.0.0.0:4000`. The server starts a multithread Tokio runtime. Input validation and large +round-record updates must not prevent the RPC transports from receiving WebSocket heartbeats. Actix +HTTP workers retain their own runtimes; the server does not use Actix actors or +`actix_web::rt::spawn`. diff --git a/agent/flow-trace/04_DKG_AND_COMPUTATION.md b/agent/flow-trace/04_DKG_AND_COMPUTATION.md index 3e9c58c523..b3f7b364e9 100644 --- a/agent/flow-trace/04_DKG_AND_COMPUTATION.md +++ b/agent/flow-trace/04_DKG_AND_COMPUTATION.md @@ -1128,15 +1128,15 @@ The OpenVM host streams the round to the guest one item at a time: a bincode hea parameters, on-chain indices, published commitments and metadata), every ciphertext in index order, then the selected ciphertexts again. The guest keeps a hash of each ciphertext from the first pass and refuses a second-pass ciphertext that differs. The native host and guest run the same -`SecureProcess` with the project's policy. The guest commits nine 32-byte ABI words in this order: chain ID, -Interfold address, full uint256 E3 ID, encryption scheme ID, committee public-key hash, output hash, -SAFE commitment, parameter hash, and input root. It reveals SHA-256 of these 288 bytes. - -The OpenVM worker generates an application proof, recursive aggregate, and Halo2 EVM proof. -It checks the configured executable and VM commitments and verifies the EVM proof against the -native journal before it returns a seal. The app returns the seal, parameter hash, and input root -in one ABI-encoded proof. Missing configuration or a failed proof cannot select a fake-proof mode. -See `crates/openvm-prover/README.md` for the build and deployment boundary. Existing RISC Zero +`SecureProcess` with the project's policy. The guest commits nine 32-byte ABI words in this order: +chain ID, Interfold address, full uint256 E3 ID, encryption scheme ID, committee public-key hash, +output hash, SAFE commitment, parameter hash, and input root. It reveals SHA-256 of these 288 bytes. + +The OpenVM worker generates an application proof, recursive aggregate, and Halo2 EVM proof. It +checks the configured executable and VM commitments and verifies the EVM proof against the native +journal before it returns a seal. The app returns the seal, parameter hash, and input root in one +ABI-encoded proof. Missing configuration or a failed proof cannot select a fake-proof mode. See +`crates/openvm-prover/README.md` for the build and deployment boundary. Existing RISC Zero deployment records are not migrated by this source change. The request-time scheme verifier reconstructs the protocol fields from on-chain state. The E3 @@ -1971,8 +1971,8 @@ commitment and every input is computed over — and matches the starter template `MyProgram.publishInput` inserts the commitment directly. Every E3 program exports `policy()` beside `fhe_processor`, so the guest and the dev runner need not know which program they are running. -The support program manifest points to the canonical CRISP source in `examples/CRISP/program`. -A policy change requires a new OpenVM executable, derived application commitments, and matching +The support program manifest points to the canonical CRISP source in `examples/CRISP/program`. A +policy change requires a new OpenVM executable, derived application commitments, and matching receipt-verifier deployment. Do not reuse a legacy RISC Zero image ID or an aggregation key for another VM configuration. @@ -1982,9 +1982,9 @@ round grows. The allocator is part of the guest executable, so changing it chang commitments that the receipt verifiers bind. `interfold program start` uses `program.openvm` to locate the repository, worker executable, and -worker configuration. The HTTP service validates this configuration before it accepts work. -Proving artifacts and machine-specific paths stay outside Git. Explicit development mode remains -separate from the real-proof service. +worker configuration. The HTTP service validates this configuration before it accepts work. Proving +artifacts and machine-specific paths stay outside Git. Explicit development mode remains separate +from the real-proof service. File: `examples/CRISP/packages/crisp-contracts/tests/openvm-service.test.ts` diff --git a/agent/flow-trace/08_DATA_AVAILABILITY.md b/agent/flow-trace/08_DATA_AVAILABILITY.md index 02d4b6258d..78617680c4 100644 --- a/agent/flow-trace/08_DATA_AVAILABILITY.md +++ b/agent/flow-trace/08_DATA_AVAILABILITY.md @@ -73,10 +73,10 @@ bytes from Avail, and verify their hash. hash without an accepted VectorX receipt can therefore never enter the final computation. The aggregate callback uses the same two-proof order. Before the server spends Avail funds, it calls -`CRISPProgram.verify` as an Ethereum read with the output hash, SAFE commitment, and OpenVM -proof. Only an output that passes that exact on-chain verifier becomes a durable Avail job. The job -ID excludes the proof seal, so another valid seal for the same output is an idempotent retry instead -of a second paid publication. The job ID also uses the canonical decimal E3 identifier, so an alias +`CRISPProgram.verify` as an Ethereum read with the output hash, SAFE commitment, and OpenVM proof. +Only an output that passes that exact on-chain verifier becomes a durable Avail job. The job ID +excludes the proof seal, so another valid seal for the same output is an idempotent retry instead of +a second paid publication. The job ID also uses the canonical decimal E3 identifier, so an alias such as `042` selects the same job as `42` rather than a second paid publication. The server also refuses the job while the input window is open: a proof over the current root could otherwise become stale after another vote, after the Avail fee was already paid. The compute server retries a @@ -211,10 +211,10 @@ The boundaries are intentional: Late input finalization is best-effort recovery, not a new seven-day availability promise. The contract can accept a receipt through `computeDeadline`, but the E3 can complete only if enough of -the compute window remains to produce the OpenVM proof, publish the aggregate ciphertext to -Avail, wait for its VectorX proof, and submit the output on Ethereum. The server therefore refuses -to start an aggregate Avail job unless more than three hours remain. Operators must alert well -before that cutoff instead of treating `computeDeadline` as a useful finalization target. +the compute window remains to produce the OpenVM proof, publish the aggregate ciphertext to Avail, +wait for its VectorX proof, and submit the output on Ethereum. The server therefore refuses to start +an aggregate Avail job unless more than three hours remain. Operators must alert well before that +cutoff instead of treating `computeDeadline` as a useful finalization target. The boundary tests use the contract timestamp directly. They cover these cases: @@ -337,8 +337,8 @@ run in the request transaction, before the requester pays the fee. replacement costs one bridge request and no second publication. A job record written before the coordinates were kept decodes with no coordinates, keeps its candidate proof, and needs operator recovery. -- The server verifies an aggregate OpenVM proof before it creates an Avail output job. An - arbitrary caller of the output webhook cannot spend the Avail account on an invalid output. +- The server verifies an aggregate OpenVM proof before it creates an Avail output job. An arbitrary + caller of the output webhook cannot spend the Avail account on an invalid output. - The compute server retries a transient callback five times, but this callback is not a durable outbox. If that process exits after it receives a proof but before CRISP accepts the callback, operators must recover the result or resubmit the computation. The durable Avail worker starts @@ -544,8 +544,8 @@ provider, or on a later adapter, keeps working. The normal unit and contract suites do not reproduce the deployed OpenVM guest. Before deployment, build the guest and worker from the pinned source and validate their application commitments with the worker's `check` command. Deploy a checked Halo2 artifact and bind both verification gates to -the same receipt identity. Follow `crates/openvm-prover/README.md` and the provenance procedure. -A native computation does not replace this proof check. +the same receipt identity. Follow `crates/openvm-prover/README.md` and the provenance procedure. A +native computation does not replace this proof check. After the guest is rebuilt, run the full local CRISP Playwright flow and one Sepolia round with real Avail Turing and VectorX. Observe this complete event order: diff --git a/crates/compute-provider/Readme.md b/crates/compute-provider/Readme.md index 25a5b37973..758c6449fc 100644 --- a/crates/compute-provider/Readme.md +++ b/crates/compute-provider/Readme.md @@ -104,8 +104,8 @@ published, and `recomputed`, the commitment derived from the bytes. `matches_com `select` receives an `InputRecord` per input: the same fields without the ciphertext bytes. The Secure Process reads each ciphertext once to build its leaf and does not keep it, so selection works -on what remains. The selected ciphertexts are read again, and each is refused unless it hashes to the -`ciphertext_hash` of its first read. +on what remains. The selected ciphertexts are read again, and each is refused unless it hashes to +the `ciphertext_hash` of its first read. `InputPolicy::default()` is the behaviour every E3 program had before policies existed. The leaf is the ciphertext's own SAFE commitment, and every input is computed over. A program whose contract diff --git a/crates/openvm-prover/README.md b/crates/openvm-prover/README.md index a58ed3a350..20843eefa8 100644 --- a/crates/openvm-prover/README.md +++ b/crates/openvm-prover/README.md @@ -7,13 +7,13 @@ of an existing receipt. Existing deployment records and legacy RISC Zero contrac ## Pieces -| Piece | What it is | -| ---------------------------------------- | -------------------------------------------------------------------------- | -| `guest/` in the project | The OpenVM guest. Its own workspace, built with `cargo openvm` | -| `.interfold/support/openvm/service` | The proving service: `e3-program-server` with `e3-openvm-host` as runner | -| `.interfold/support/openvm/compile` | Builds the guest, keys, receipt identity, worker configuration and service | -| `.interfold/support/openvm/start` | Starts the service | -| `interfold-openvm-prover` (this crate) | The worker. A separate process, in a CPU build and a CUDA build | +| Piece | What it is | +| -------------------------------------- | -------------------------------------------------------------------------- | +| `guest/` in the project | The OpenVM guest. Its own workspace, built with `cargo openvm` | +| `.interfold/support/openvm/service` | The proving service: `e3-program-server` with `e3-openvm-host` as runner | +| `.interfold/support/openvm/compile` | Builds the guest, keys, receipt identity, worker configuration and service | +| `.interfold/support/openvm/start` | Starts the service | +| `interfold-openvm-prover` (this crate) | The worker. A separate process, in a CPU build and a CUDA build | `interfold init` copies the service folder and pins the guest's Interfold crates to the template's commit. In this repository, `templates/default` and `examples/CRISP` link the folder from @@ -63,8 +63,8 @@ program: ``` With `backend: auto` the service runs the CUDA worker's `probe` at startup. When that opens a GPU, -the CUDA worker proves; when there is no CUDA worker, no GPU, or no driver, the CPU worker proves and -the service logs why. `backend: cuda` refuses to start without a working GPU, and `backend: cpu` +the CUDA worker proves; when there is no CUDA worker, no GPU, or no driver, the CPU worker proves +and the service logs why. `backend: cuda` refuses to start without a working GPU, and `backend: cpu` never tries one. ## Compile, deploy and start @@ -89,45 +89,45 @@ interfold program start ``` The service picks its worker, then runs the worker's `check`. That loads the application, -aggregation and Halo2 keys and both KZG parameter files, verifies the verifier artifact's digest, and -recomputes the identity from the executable, before any request is accepted. +aggregation and Halo2 keys and both KZG parameter files, verifies the verifier artifact's digest, +and recomputes the identity from the executable, before any request is accepted. ## Worker commands -| Command | Purpose | -| ------------------------------------------------------------------------------ | ------------------------------------------ | -| `prepare ` | Aggregation key and `identity.json` | -| `write-config ` | The configuration below | -| `probe` | Succeeds only for a CUDA build with a GPU | -| `check ` | Loads and checks every artifact | -| `prove ` | Proves and verifies one round | -| `verify ` | Verifies an existing proof | +| Command | Purpose | +| ----------------------------------------------------------------------------- | ----------------------------------------- | +| `prepare ` | Aggregation key and `identity.json` | +| `write-config ` | The configuration below | +| `probe` | Succeeds only for a CUDA build with a GPU | +| `check ` | Loads and checks every artifact | +| `prove ` | Proves and verifies one round | +| `verify ` | Verifies an existing proof | `prove` reads the guest input items the host wrote, proves the application, aggregates it, generates the Halo2 EVM proof, and verifies it with the configured EVM verifier against the expected journal and both application commitments before it writes a seal. There is no fake-proof mode. -| Configuration field | Value | -| ---------------------- | ------------------------------------------------------------- | -| `app_pk` | The guest application proving key | -| `executable` | The guest VM executable | -| `aggregation_pk` | The aggregation key from `prepare` | -| `halo2_pk` | The Halo2 proving key | -| `halo2_params_dir` | The KZG parameter directory | -| `verifier_artifact` | The EVM verifier bytecode JSON | -| `verifier_sha256` | Its SHA-256 digest, lowercase hexadecimal | -| `app_commit` | The `app_commit` object from `identity.json` | +| Configuration field | Value | +| ---------------------- | -------------------------------------------------------------- | +| `app_pk` | The guest application proving key | +| `executable` | The guest VM executable | +| `aggregation_pk` | The aggregation key from `prepare` | +| `halo2_pk` | The Halo2 proving key | +| `halo2_params_dir` | The KZG parameter directory | +| `verifier_artifact` | The EVM verifier bytecode JSON | +| `verifier_sha256` | Its SHA-256 digest, lowercase hexadecimal | +| `app_commit` | The `app_commit` object from `identity.json` | | `segment_memory_bytes` | The proving segment memory limit (`compile` defaults to 8 GiB) | ## Service settings -| Variable | Default | Meaning | -| ----------------------------- | ------------------- | --------------------------------------------- | -| `OPENVM_BIND_ADDR` | `127.0.0.1:13151` | Listener | -| `OPENVM_MAX_REQUEST_BYTES` | 128 MiB | Largest `/run_compute` body | -| `MAX_CONCURRENT_COMPUTATIONS` | 1 | Rounds proved at once | -| `OPENVM_CHECK_TIMEOUT_SECS` | 1800 | Deadline for the startup `check` | -| `OPENVM_PROVE_TIMEOUT_SECS` | 86400 | Deadline for one proof; the worker is stopped | +| Variable | Default | Meaning | +| ----------------------------- | ----------------- | --------------------------------------------- | +| `OPENVM_BIND_ADDR` | `127.0.0.1:13151` | Listener | +| `OPENVM_MAX_REQUEST_BYTES` | 128 MiB | Largest `/run_compute` body | +| `MAX_CONCURRENT_COMPUTATIONS` | 1 | Rounds proved at once | +| `OPENVM_CHECK_TIMEOUT_SECS` | 1800 | Deadline for the startup `check` | +| `OPENVM_PROVE_TIMEOUT_SECS` | 86400 | Deadline for one proof; the worker is stopped | A request is admitted before its body is read, and a request beyond capacity gets 429. Jobs are in memory: a restart loses accepted jobs, and operators must reconcile them. Callbacks are retried with @@ -169,15 +169,15 @@ pnpm openvm contract-test # receipt and journal contracts ``` `pnpm openvm proof-test` verifies an externally supplied proof on an in-memory chain. It needs -`OPENVM_TEST_IDENTITY`, `OPENVM_TEST_JOURNAL`, `OPENVM_TEST_VERIFIER`, `OPENVM_TEST_VERIFIER_SHA256`, -and `OPENVM_TEST_PROOF` (proof JSON) or `OPENVM_TEST_SEAL` (worker seal). - -`pnpm openvm service-e2e` runs a live round: CRISP input submission and indexing, the running -OpenVM service, the callback, and ciphertext publication. It needs an isolated loopback RPC with -chain ID 31337 (use Anvil for long rounds) and a running service started with -`pnpm openvm service-start` after `pnpm openvm compile`. Build the CRISP server with -`pnpm openvm crisp-server-build --release` and generate secure-8192 ballots with -`pnpm openvm fixture `. Set: +`OPENVM_TEST_IDENTITY`, `OPENVM_TEST_JOURNAL`, `OPENVM_TEST_VERIFIER`, +`OPENVM_TEST_VERIFIER_SHA256`, and `OPENVM_TEST_PROOF` (proof JSON) or `OPENVM_TEST_SEAL` (worker +seal). + +`pnpm openvm service-e2e` runs a live round: CRISP input submission and indexing, the running OpenVM +service, the callback, and ciphertext publication. It needs an isolated loopback RPC with chain ID +31337 (use Anvil for long rounds) and a running service started with `pnpm openvm service-start` +after `pnpm openvm compile`. Build the CRISP server with `pnpm openvm crisp-server-build --release` +and generate secure-8192 ballots with `pnpm openvm fixture `. Set: | Variable | Meaning | | ----------------------------- | ---------------------------------------------------------- | diff --git a/crates/openvm-prover/src/main.rs b/crates/openvm-prover/src/main.rs index d2b27c5fbe..039996a9a1 100644 --- a/crates/openvm-prover/src/main.rs +++ b/crates/openvm-prover/src/main.rs @@ -9,6 +9,8 @@ //! the configuration every other action reads. //! - `probe`: succeeds when this build can use a GPU on this machine. //! - `check `: loads every key and the verifier, before a service accepts work. +//! - `execute `: runs the guest without proving and checks that it +//! reveals the journal's digest. A cheap check of a round, and of the guest against the host. //! - `prove `: proves and verifies a round. //! - `verify `: verifies an existing proof. @@ -233,6 +235,32 @@ fn probe() -> Result<()> { eyre::bail!("This worker was built without CUDA") } +/// Runs the guest over `input` without proving it and checks that it reveals the digest of the +/// journal the host expects. +fn execute(config: &Config, input: &Path, journal: &Path) -> Result<()> { + let journal = read_limited(journal, 288)?; + ensure!(journal.len() == 288, "Expected nine journal words"); + let app_pk: AppProvingKey = read_object_from_file(&config.app_pk)?; + let exe: VmExe = read_object_from_file(&config.executable)?; + let sdk = Sdk::builder() + .app_pk(app_pk) + .agg_params(AggregationSystemParams::default()) + .build()?; + let (public_values, segments) = + sdk.execute_metered(exe, read_items(fs::File::open(input)?)?)?; + let instructions: u64 = segments.iter().map(|segment| segment.num_insns).sum(); + eprintln!( + "OpenVM: executed {instructions} instructions in {} segments", + segments.len() + ); + ensure!( + public_values == Sha256::digest(&journal).to_vec(), + "The guest revealed a digest that differs from the host's journal" + ); + eprintln!("OpenVM: the guest revealed the digest of the host's journal"); + Ok(()) +} + fn absolute(path: &Path) -> Result { fs::canonicalize(path) .map_err(|error| eyre::eyre!("Cannot resolve {}: {error}", path.display())) @@ -284,7 +312,7 @@ fn write_config(paths: &[PathBuf]) -> Result<()> { fn main() -> Result<()> { let mut args = std::env::args_os().skip(1); let action = args.next().ok_or_else(|| { - eyre::eyre!("Expected prepare, write-config, probe, check, prove, or verify") + eyre::eyre!("Expected prepare, write-config, probe, check, execute, prove, or verify") })?; if action == "probe" { ensure!(args.next().is_none(), "Unexpected arguments"); @@ -339,9 +367,14 @@ fn main() -> Result<()> { eprintln!("OpenVM: the keys, parameters, verifier, and identity are consistent"); return Ok(()); } + if action == "execute" { + let paths: Vec = args.map(PathBuf::from).collect(); + ensure!(paths.len() == 2, "Expected the input and the journal"); + return execute(&config, &paths[0], &paths[1]); + } ensure!( action == "prove" || action == "verify", - "Expected prepare, write-config, probe, check, prove, or verify" + "Expected prepare, write-config, probe, check, execute, prove, or verify" ); let paths: Vec = args.map(PathBuf::from).collect(); ensure!( diff --git a/crates/support-scripts/openvm/compile b/crates/support-scripts/openvm/compile index a5ecbab413..0edf07ae00 100755 --- a/crates/support-scripts/openvm/compile +++ b/crates/support-scripts/openvm/compile @@ -16,7 +16,7 @@ # OPENVM_SETUP_DIR what `cargo openvm setup` wrote (default ~/.openvm) # OPENVM_SEGMENT_MEMORY_BYTES the proving segment memory limit (default 8 GiB, fits a 16 GB GPU) # CARGO_OPENVM the cargo-openvm command (default `cargo openvm`) -# OPENVM_BUILD_LOCKED=1 build the guest with --locked +# OPENVM_BUILD_LOCKED=1 build the guest with --locked (read by cargo-openvm) set -euo pipefail PROJECT="$(pwd)" @@ -42,11 +42,10 @@ sha256() { mkdir -p "$OUT" echo "Building the OpenVM guest" -locked=() -if [ "${OPENVM_BUILD_LOCKED:-0}" = 1 ]; then locked=(--locked); fi +# cargo-openvm reads OPENVM_BUILD_LOCKED itself and passes --locked to the guest build. RUSTFLAGS="${RUSTFLAGS:-} --cfg crisp_openvm --cfg crisp_fhe_optimized" \ "${CARGO_OPENVM[@]}" build --manifest-path "$GUEST/Cargo.toml" --target-dir "$OUT/guest-target" \ - --output-dir "$OUT/guest" ${locked[@]+"${locked[@]}"} + --output-dir "$OUT/guest" EXE="$OUT/guest/e3-openvm-guest.vmexe" KEYS="$OUT/keys" diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index 06733b791d..9aac958753 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -34,7 +34,7 @@ conditions in [Privacy limits](#privacy-limits): | Secret ballot | The client encrypts each ballot with BFV under the committee public key. Only the encrypted sum is decrypted. Decryption needs T + 1 key shares, so no single ciphernode can decrypt. | | Receipt resistance | A voter can replace their ballot in the same slot. Anyone can add a mask (an encrypted zero ballot) to any eligible slot. On-chain, a vote, an update, and a mask look the same. | | Eligibility | A Noir proof shows that the slot is in the round census, or that the slot has on-chain voting power. | -| Verifiable result | `CRISPProgram.verify` checks a RISC Zero proof of the sum. The Interfold contract checks the decryption proof when the committee publishes the result. | +| Verifiable result | `CRISPProgram.verify` checks an OpenVM proof of the sum. The Interfold contract checks the decryption proof when the committee publishes the result. | | Sender privacy | The CRISP server can relay inputs, so the chain shows the relay address instead of the voter address. Relaying is configurable, and it is off on Ethereum mainnet by default. | A mask adds an encryption of zero to the ciphertext that is already in a slot. The result is a new @@ -108,7 +108,7 @@ requested and when the encrypted output is published. The | `setMerkleRoot` | Owner (the CRISP server key) | Stores the census Merkle root for a round that uses a census tree. | | `publishInput` | Voter wallet or server relay | Verifies the Noir proof and the availability signature of the server. Reserves the input leaf and emits `InputCommitted`. | | `finalizeInput` | Any account (usually the server) | Verifies the data-availability receipt for the committed ciphertext hash. Emits `InputPublished`. | -| `verify` | Interfold contract, at the output | Reverts with `InputAvailabilityPending` while an input waits for finalization. Checks the RISC Zero proof against the parameters hash and the input root. | +| `verify` | Interfold contract, at the output | Reverts with `InputAvailabilityPending` while an input waits for finalization. Checks the OpenVM receipt against the parameters hash and the input root. | | `decodeTally` | Anyone (view) | Decodes the plaintext output into one count per option. | The round parameters include a census mode. The census mode selects who can vote and which Noir @@ -192,6 +192,7 @@ The tree shows the top-level content of `examples/CRISP` that is tracked in Git. | `docs/` | `PROOF_AGGREGATION_AND_ZK.md`: local modes for DKG proof aggregation. | | `packages/` | `crisp-contracts` (Hardhat project with `CRISPProgram.sol`), `crisp-sdk` (`@crisp-e3/sdk`), and `crisp-zk-inputs` (WASM bindings). | | `program/` | The E3 program crate `e3-user-program`: `fhe_processor` and the input `policy`. | +| `guest/` | The OpenVM guest that proves `program/`. Its own Cargo workspace, built by `interfold program compile`. | | `scripts/` | Shell and Node scripts for setup, local services, circuits, tests, and publication. | | `server/` | The coordination server, the CLI, and the cron client. | | `test/` | The Playwright and Synpress end-to-end test. | @@ -200,9 +201,10 @@ The tree shows the top-level content of `examples/CRISP` that is tracked in Git. | `.env.example` | Template for the keys that `scripts/setup_testnet.sh` reads. | | `docker-compose.yaml` | An optional development container that mounts the repository and publishes ports 8545, 3000, and 4000. | -The production RISC Zero guest is in `crates/support` at the repository root. It includes the same -`fhe_processor` and `policy` code as `program/`. The CRISP deploy script reads the image ID from -`crates/support/contracts/ImageID.sol`. +The OpenVM guest is in `guest/`, and the proving service is in `.interfold/support/openvm`. Both +link `program/`, so they run the same `fhe_processor` and `policy` as the native host and agree with +`CRISPProgram`. `interfold program compile` builds the guest and writes its receipt identity, which +the CRISP deploy script reads unless `OPENVM_*` settings name another. ## Further reading diff --git a/docs/pages/CRISP/setup.mdx b/docs/pages/CRISP/setup.mdx index b5237673ac..87673cf2d8 100644 --- a/docs/pages/CRISP/setup.mdx +++ b/docs/pages/CRISP/setup.mdx @@ -20,23 +20,23 @@ repository. Run all `pnpm` commands on this page from `examples/CRISP`. ## Prerequisites -| Tool | Version | Used by | -| --------------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------- | -| Git | Any | Clone and submodules | -| [Rust](https://rust-lang.org/tools/install/) | 1.91.1 (`rust-toolchain.toml`) | Server, CLI, program, and the `interfold` CLI | -| [Node.js](https://nodejs.org/en/download) | 22.x (CI uses `NODE_VERSION: 22`) | Client, SDK, contracts, and scripts | -| [pnpm](https://pnpm.io) | 10.7.1 (`packageManager` in `package.json`) | All JavaScript packages | -| [Foundry](https://getfoundry.sh) | Any | `anvil`, the local chain that `scripts/dev.sh` starts | -| [`yq`](https://github.com/mikefarah/yq) | Any | `scripts/dev_cipher.sh` reads node addresses from the config | -| [`nargo`](https://noir-lang.org/docs/installation) | `v1.0.0-beta.26` (`NOIR_TOOLCHAIN` in CI) | Circuit builds in `pnpm dev:setup` and `pnpm compile:circuits` | -| [`bb`](https://barretenberg.aztec.network/docs/getting_started) | 5.1.0 (`crates/zk-prover/versions.json`) | Verification keys and generated verifiers | -| Python 3 | Any | `scripts/compile_circuits.sh` patches the generated verifiers | -| A browser wallet, for example [MetaMask](https://metamask.io) | Any | The client | -| Docker | Any | Only for real RISC Zero proofs and `interfold program compile` or `upload` | +| Tool | Version | Used by | +| --------------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------- | +| Git | Any | Clone | +| [Rust](https://rust-lang.org/tools/install/) | 1.91.1 (`rust-toolchain.toml`) | Server, CLI, program, and the `interfold` CLI | +| [Node.js](https://nodejs.org/en/download) | 22.x (CI uses `NODE_VERSION: 22`) | Client, SDK, contracts, and scripts | +| [pnpm](https://pnpm.io) | 10.7.1 (`packageManager` in `package.json`) | All JavaScript packages | +| [Foundry](https://getfoundry.sh) | Any | `anvil`, the local chain that `scripts/dev.sh` starts | +| [`yq`](https://github.com/mikefarah/yq) | Any | `scripts/dev_cipher.sh` reads node addresses from the config | +| [`nargo`](https://noir-lang.org/docs/installation) | `v1.0.0-beta.26` (`NOIR_TOOLCHAIN` in CI) | Circuit builds in `pnpm dev:setup` and `pnpm compile:circuits` | +| [`bb`](https://barretenberg.aztec.network/docs/getting_started) | 5.1.0 (`crates/zk-prover/versions.json`) | Verification keys and generated verifiers | +| Python 3 | Any | `scripts/compile_circuits.sh` patches the generated verifiers | +| A browser wallet, for example [MetaMask](https://metamask.io) | Any | The client | +| `cargo-openvm` v2.0.2 | v2.0.2 | Only for real OpenVM proofs (`CRISP_REAL_PROOFS=1`) | Install `nargo` with `noirup -v v1.0.0-beta.26`. Other `nargo` versions can fail to compile the -circuits. A RISC Zero installation is not necessary for local development, because -`scripts/dev_program.sh` starts the program server in dev mode. +circuits. OpenVM is not necessary for local development, because the local scripts start the program +server in dev mode unless `CRISP_REAL_PROOFS=1`. ## Build and start CRISP @@ -47,13 +47,9 @@ circuits. A RISC Zero installation is not necessary for local development, becau ```bash git clone https://github.com/theinterfold/interfold.git cd interfold -git submodule update --init --recursive cd examples/CRISP ``` -The CRISP contracts import the `risc0-ethereum` submodule at -`examples/CRISP/packages/crisp-contracts/lib/risc0-ethereum`. - ### Choose a local profile This step is optional. `pnpm dev:setup` copies the example file when `crisp.dev.env` does not exist. @@ -143,7 +139,10 @@ includes these contracts: `CRISP_SKIP_PROOF_AGGREGATION=false`, the script sets `ENABLE_ZK_VERIFICATION=true`, and the deployment uses the real BFV verifiers. - `CRISPProgram`, the two generated Noir ballot verifiers, and `SelfRegistry`. -- `MockRISC0Verifier`, `MockVotingToken`, and `MockCrispDataAvailabilityVerifier`. +- `MockOpenVmReceiptVerifier` (with `CRISP_UNPROVED_TEST=1`, which the local scripts set unless + `CRISP_REAL_PROOFS=1`), `MockVotingToken`, and `MockCrispDataAvailabilityVerifier`. With + `CRISP_REAL_PROOFS=1`, the deployment instead deploys the OpenVM receipt verifier for the guest + that `interfold program compile` built. After the deployment, the script writes the new contract addresses into three files. You do not copy addresses by hand: @@ -206,7 +205,7 @@ chains: # e3_program, interfold, ciphernode_registry, bonding_registry, # slashing_manager, and fee_token: updated by the deployment program: - dev: true + dev: false nodes: cn1: quic_port: 9201 @@ -227,8 +226,8 @@ nodes: mode is `avail`. - Nodes `cn3` to `cn5` use QUIC ports 9203 to 9205 and control ports 50503 to 50505. Each node peers with `cn1`. -- `scripts/dev_program.sh` always passes `--dev true`. For this reason, `program.dev` has no effect - on `pnpm dev:up`. +- `scripts/lib/dev_config.sh` sets `E3_PROGRAM__DEV=true` unless `CRISP_REAL_PROOFS=1`, so + `pnpm dev:up` runs the development runner by default although the file sets `program.dev: false`. For all node configuration keys, see [Configuration](/reference/configuration). @@ -248,7 +247,7 @@ environment (`server/src/config.rs`). | `VOTING_START_BUFFER_SECONDS` | `20` in the example file. Default `120`. | Time for the request transaction to be mined before the input window starts | | `E3_PARAM_SET` | `0` | `0` is `insecure-512`, `2` is `secure-8192`. Ethereum mainnet requires `2`. | | `E3_COMMITTEE_SIZE` | `0` | `0` is `minimum` (N = 3, T = 1), `1` is `micro` (N = 9, T = 4), `2` is `small` (N = 19, T = 9) | -| `E3_COMPUTE_PROVIDER_NAME`, `E3_COMPUTE_PROVIDER_PARALLEL`, `E3_COMPUTE_PROVIDER_BATCH_SIZE` | `RISC0`, `false`, `4` | Compute provider parameters sent with the request. The batch size must be a power of 2. | +| `E3_COMPUTE_PROVIDER_NAME`, `E3_COMPUTE_PROVIDER_PARALLEL`, `E3_COMPUTE_PROVIDER_BATCH_SIZE` | `OpenVM`, `false`, `4` | Compute provider parameters sent with the request. The batch size must be a power of 2. | | `DATA_AVAILABILITY_MODE` | `mock` | `mock` or `avail`. Without a value, the mode is `mock` for chain IDs 31337 and 1337 and `avail` for other chains. `mock` is allowed only on those two chains. | | `AVAIL_RPC_URL`, `AVAIL_BRIDGE_API_URL`, `AVAIL_APP_ID`, `AVAIL_SEED` | Empty | Avail access and the funded Avail account that pays for `submit_data` | | `AVAIL_PROOF_LEAD_SECONDS` | `10800` | Minimum time before the input deadline when an Avail publication starts. In Avail mode, it must equal `CRISPProgram.availabilityFinalizationWindow()`. | @@ -293,47 +292,25 @@ Vite reads `client/.env` when the client starts or builds. | `VITE_E3_REQUESTERS` | First two Anvil accounts | Comma-separated requester addresses. The client shows rounds from these requesters. | | `VITE_ENABLE_TEST_TOKEN_MINT` | `true` | Shows the `+ Mint test tokens` button on test networks. It is always off on mainnet. | -### Real proofs with Boundless +### Real proofs with OpenVM -By default, the program server runs without a proving backend. To make real RISC Zero proofs with -[Boundless](https://docs.boundless.network/), set the `program` section of `interfold.config.yaml`: +By default, the local scripts run the development runner, which makes no proof. To prove rounds with +OpenVM on your machine, build the workers and set the `program` section of `interfold.config.yaml` +(see [Compute Provider](/build/e3-program/compute-provider#run-a-compute-provider)): ```yaml filename="interfold.config.yaml" program: dev: false - risc0: - risc0_dev_mode: 0 # 0 = Boundless, 1 = dev mode (the default) - boundless: - rpc_url: 'https://sepolia.infura.io/v3/YOUR_KEY' - private_key: 'YOUR_PRIVATE_KEY' # wallet that pays for proofs - pinata_jwt: 'YOUR_PINATA_JWT' # uploads programs to IPFS - ipfs_gateway_url: 'https://your-gateway.mypinata.cloud' - program_url: 'https://your-gateway.mypinata.cloud/ipfs/YOUR_CID' - onchain: true # the default. false sends off-chain requests. + openvm: + prover_bin: /opt/openvm/interfold-openvm-prover + prover_bin_cuda: /opt/openvm/interfold-openvm-prover-cuda # optional + backend: auto # a working GPU when there is one, the CPU otherwise ``` -The gateway must allow full, unauthenticated downloads by Boundless provers. These offer settings -are optional (`crates/config/src/program_config.rs`): - -| Key | Default | -| --------------------- | ------------- | -| `min_price_eth` | `0.00005` | -| `max_price_eth` | `0.004` | -| `timeout_secs` | `28800` (8 h) | -| `lock_timeout_secs` | `14400` (4 h) | -| `ramp_up_secs` | `7200` (2 h) | -| `lock_collateral_zkc` | `100.0` | - -`pnpm dev:up` always starts the program server in dev mode. To use Boundless, start the program -server with `interfold program start` from `examples/CRISP`. This command runs the program server in -a Docker container. - -When you change the guest program, upload it again and update `program_url`: - -1. Run `interfold program compile`. The command builds the guest in a Docker container. -2. Run `interfold program upload`. The command reads `pinata_jwt` and `ipfs_gateway_url` from the - configuration and uploads the guest to Pinata. -3. Copy the `Program URL` from the output into `program_url`. +Then set `CRISP_REAL_PROOFS=1` in `crisp.dev.env` and run `pnpm dev:setup` again. With it, +`interfold program compile` builds `examples/CRISP/guest` and its keys, the deployment deploys the +receipt verifier for that guest, and `interfold program start` serves real proofs. A changed program +or policy has a new receipt identity, so compile and deploy again after you change either. ## Run single components @@ -474,7 +451,6 @@ ballots are lost. | Symptom | Cause | Fix | | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| `pnpm dev:setup` fails with `HHE902` and `RiscZeroGroth16Verifier.sol doesn't exist` | The `risc0-ethereum` submodule is missing. | Run `git submodule update --init --recursive` from the repository root. | | `dev_cipher.sh` prints `ERROR: only / ciphernodes stayed up` | The `interfold` binary does not match the profile, or another node error. | Read the node output above the table. For a missing Cargo feature, run `pnpm dev:setup` again. | | `Invalid CRISP_BFV_PRESET` or `Invalid CRISP_SKIP_PROOF_AGGREGATION` | A value in `crisp.dev.env` is not allowed. | Use `insecure-512` or `secure-8192`, and `true` or `false`. | | The server stops at startup with `DATA_AVAILABILITY_MODE=mock is allowed only on local development chains` | `CHAIN_ID` is not 31337 or 1337 and the mode is `mock`. | Set `DATA_AVAILABILITY_MODE=avail` and the Avail settings. | diff --git a/docs/pages/build/e3-program/complete-example.mdx b/docs/pages/build/e3-program/complete-example.mdx index 254c8b6cc2..7eca091098 100644 --- a/docs/pages/build/e3-program/complete-example.mdx +++ b/docs/pages/build/e3-program/complete-example.mdx @@ -21,8 +21,9 @@ Make a project with `interfold init` and complete its setup. See [Quick Start](/ Template paths on this page are relative to the project root. Paths that start with `crates/` or `packages/` are in the Interfold repository. -The template runs in dev mode (`program.dev: true` in `interfold.config.yaml`). The compute proof is -a mock, and a mock RISC Zero verifier accepts it. The rest of the flow is the same as in production. +The local scripts run in dev mode (`E3_PROGRAM__DEV=true`, unless `TEMPLATE_REAL_PROOFS=1`). The +compute proof is a mock, and `MockOpenVmReceiptVerifier` accepts it. The rest of the flow is the +same as in production. ## The E3 at a glance @@ -88,10 +89,11 @@ Run `pnpm dev:all` in the project root. `scripts/dev_all.sh` calls contracts with mocks, and then calls `deployTemplate` in `deploy/default.ts`. `deployTemplate` does these actions in order: -1. Deploys `MockRISC0Verifier` and the `ImageID` library. -2. Deploys `Risc0BfvCiphertextVerifier` with the mock verifier and `ImageID.PROGRAM_ID`. +1. Deploys `MockOpenVmReceiptVerifier` (with `TEMPLATE_UNPROVED_TEST=1` on the local chain) or an + `OpenVmReceiptVerifier` for the guest that `interfold program compile` built. +2. Deploys `OpenVmBfvCiphertextVerifier` with that receipt verifier and its `imageId`. 3. Calls `setCiphertextVerifier` for `keccak256("fhe.rs:BFV")`. -4. Deploys `MyProgram` with the Interfold address, the mock verifier, and the image ID. +4. Deploys `MyProgram` with the Interfold address, the receipt verifier, and the `imageId`. 5. Calls `registerE3Program`. The Interfold contract probes `supportsInterface` and emits `E3ProgramRegistered`. @@ -148,7 +150,9 @@ body has the E3 ID, the proof domain, the parameters, the inputs, and the callba The dev runner (`crates/support-scripts/dev/src/main.rs`) builds a `ComputeManager` with your `fhe_processor` from `program/src/lib.rs`. `start(policy())` builds the input tree, runs the processor, and computes the output hash, commitment, parameter hash, and input root. The runner -encodes a mock proof with the parameter hash and the input root. +encodes a mock proof with the parameter hash and the input root. With real proofs, the OpenVM +service runs the same secure process natively, proves it in `guest/`, and returns the verified +OpenVM envelope instead. ### Publish the output @@ -162,9 +166,9 @@ stores the ciphertext under its Keccak-256 hash in `.interfold/data-availability The output is not published yet, and the committee still meets its threshold. 2. `MyProgram.verifyDataAvailability` checks that the Keccak-256 hash of the raw ciphertext equals the content hash. -3. `Risc0BfvCiphertextVerifier.verify` rebuilds the journal and calls the mock verifier. +3. `OpenVmBfvCiphertextVerifier.verify` rebuilds the journal and calls the receipt verifier. 4. `MyProgram.verify` compares the parameter hash and the input root, rebuilds the journal, and - calls the mock verifier. + calls the receipt verifier. The E3 moves to `CiphertextReady`. The Interfold contract emits `CiphertextOutputReferencePublished` and `E3StageChanged`. @@ -207,7 +211,7 @@ CRISP uses the same parts with production choices: | Input submission | One `publishInput` call with ciphertext and commitment | `publishInput` with a Noir proof, then `finalizeInput` with a DA receipt | | Input leaf | The SAFE commitment | `sha256(keccak256(ciphertext) ‖ commitment ‖ slot ‖ parent)` mod the BN254 field | | Input policy | `InputPolicy::default()` | `policy::crisp()`, one input for each slot | -| Compute provider | Dev runner with a mock proof | `e3-support` container with Boundless proofs | +| Compute provider | Dev runner with a mock proof | CRISP's OpenVM service and guest, proved on the operator's GPU or CPU | | Data availability | Local file store and a hash check | `AvailVectorXDataAvailabilityVerifier` (a mock on a local chain) | | Output publisher | `server/index.ts` | `examples/CRISP/server` (`/state/add-result` webhook) | diff --git a/docs/pages/build/e3-program/compute-provider.mdx b/docs/pages/build/e3-program/compute-provider.mdx index 4e6403a6a8..7188284442 100644 --- a/docs/pages/build/e3-program/compute-provider.mdx +++ b/docs/pages/build/e3-program/compute-provider.mdx @@ -1,9 +1,8 @@ --- title: 'Compute Provider' description: - 'How the compute provider runs the secure process, proves it with RISC Zero, and returns the - output to the server that calls publishCiphertextOutput. Includes the setup for a compute - provider.' + 'How the compute provider runs the secure process, proves it with OpenVM, and returns the output + to the server that calls publishCiphertextOutput. Includes the setup for a compute provider.' --- import { Callout, Steps } from 'nextra/components' @@ -11,9 +10,10 @@ import { LinkCard, LinkCards } from '@/components/ui' # Compute Provider -The compute provider (CP) runs the secure process off-chain and proves that it ran correctly. The -Interfold repository ships one CP stack: a program server that runs the secure process, with a RISC -Zero zkVM guest for the proof. This page explains what the Interfold contract expects from a CP, how +The compute provider (CP) runs the secure process off-chain and proves that it ran correctly. Each +Interfold project proves its own E3 program: an OpenVM guest and a proving service, both built from +the project's `program/` crate, run on the operator's machine. There is no proving market, program +upload, or payment account. This page explains what the Interfold contract expects from a CP, how the Rust crates fit together, and how to run a CP. It is for E3 program developers and for the person who runs the CP. @@ -40,21 +40,56 @@ that made it. ## Components -| Component | Location | Role | -| ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------------ | -| `e3-compute-provider` | `crates/compute-provider` | `ComputeProvider` trait, `ComputeManager`, `ComputeInput`, `InputPolicy`, input tree | -| `e3-program-server` | `crates/program-server` | HTTP server with `POST /run_compute` and `GET /health`. It calls your runner function. | -| `e3-support-scripts` | `crates/support-scripts` | Called by `interfold program`. It holds the dev runner and the Docker control scripts. | -| E3 support (RISC Zero) | `crates/support` | Docker image with the RISC Zero guest, the Boundless host, and the `e3-support-app` server | -| Coordination server | `server/index.ts` (template) | Sends the job, receives the webhook, and calls `publishCiphertextOutput` | +| Component | Location | Role | +| --------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------- | +| `e3-compute-provider` | `crates/compute-provider` | `SecureProcess`, `ComputeProvider`, `ComputeManager`, `InputPolicy`, input tree | +| `e3-program-server` | `crates/program-server` | HTTP server with `POST /run_compute` and `GET /health`. It calls a runner function. | +| `e3-openvm-host` | `crates/openvm-host` | The OpenVM runner: native run, guest input, worker selection, proof envelope | +| `interfold-openvm-prover` | `crates/openvm-prover` | The worker that proves the guest. A CPU build and a CUDA build. | +| Guest | `guest/` in your project | The OpenVM guest. It links your `program/` crate. | +| Proving service and scripts | `.interfold/support/openvm` in project | The service binary and the `compile` and `start` scripts that `interfold program` runs | +| Development runner | `.interfold/support/dev` in project | An unproved runner with a mock proof, for local work | +| Coordination server | `server/index.ts` (template) | Sends the job, receives the webhook, and calls `publishCiphertextOutput` | + +`interfold init` copies both support folders into the project and pins the guest's Interfold crates +to the template's commit. + +## The secure process + +`SecureProcess` (`crates/compute-provider/src/secure_process.rs`) is the computation that every CP +reproduces. It reads a round in two passes, one ciphertext at a time: + +1. Every ciphertext, in index order. For each one it recomputes the SAFE commitment, hashes the + bytes with Keccak-256, and builds the input's leaf with your policy. Then it drops the bytes. +2. The policy's `select` runs over the records that remain: index, hash, stored commitment, + metadata, and recomputed commitment. +3. The selected ciphertexts, read again in index order. Each one is refused unless it hashes to the + value from the first pass. Your processor receives them one at a time. + +Only one ciphertext is held at a time, so the guest's 512 MiB of memory does not limit the number of +inputs. `ComputeInput::run` runs the same code over a round that is already in memory. The OpenVM +host uses that to predict the journal the guest must reveal. + +The processor takes the selected ciphertexts as an iterator: + +```rust filename="program/src/lib.rs" +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { + let mut sum = Ciphertext::zero(fhe_inputs.params); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); + sum += &ciphertext; + } + + sum.to_bytes() +} +``` -`crates/support` is a separate Cargo workspace. It reads `e3-compute-provider` and `e3-fhe-params` -through a git revision pin, not through a path. A change to `crates/compute-provider` has no effect -on the guest until that pin moves. +The processor must read every item. Keep the state that it carries between items small. ## The ComputeProvider trait -A CP implements one method (`crates/compute-provider/src/ciphertext_output.rs`): +A CP that uses `ComputeManager` implements one method +(`crates/compute-provider/src/ciphertext_output.rs`): ```rust filename="crates/compute-provider/src/ciphertext_output.rs" pub trait ComputeProvider { @@ -69,8 +104,8 @@ secure process and then calls `prove` with the same policy. It returns the provi output ciphertext from the same input selection. Use `with_published` when the policy reads the commitment or metadata of each input. -The dev runner (`crates/support-scripts/dev/src/main.rs`) is the smallest complete CP. It runs the -template processor, builds a mock proof, and serves it over HTTP: +The dev runner (`crates/support-scripts/dev/src/main.rs`) is the smallest complete CP. It runs your +processor, builds a mock proof, and serves it over HTTP: ```rust filename="crates/support-scripts/dev/src/main.rs" #[tokio::main] @@ -94,8 +129,9 @@ async fn main() -> Result<()> { } ``` -The RISC Zero host in `crates/support/host/src/lib.rs` does the same with `BoundlessProvider` and -`Risc0Provider`. +The OpenVM service (`crates/support-scripts/openvm/service/src/main.rs`) has the same shape. Its +runner is `e3_openvm_host::Prover::prove`, which runs the secure process natively, writes the +guest's input stream, runs the worker, and returns the verified proof envelope. ## The program server @@ -103,14 +139,18 @@ The program server does not send transactions. It computes, then posts the resul `callback_url` of the request. The coordination server receives that webhook and calls `publishCiphertextOutput`. -| Setting | Value | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| Bind address | `0.0.0.0:13151` (`E3ProgramServerBuilder` defaults, and fixed in `e3-support-app`) | -| Endpoints | `POST /run_compute`, `GET /health`, `HEAD /health` | -| Body limit | 10 MB of JSON in `crates/program-server` | -| Parallel jobs | 1 by default in both servers. A request over the limit gets HTTP 429. | -| Webhook | One attempt in `crates/program-server`. Up to five attempts in `e3-support-app` after a network error or HTTP 5xx, 408, or 429. | -| Response | `{"status":"processing","e3_id":""}` at once. The computation runs in the background. | +| Setting | Development runner | OpenVM service | +| ------------- | ------------------------------------------------ | ------------------------------------------------------ | +| Bind address | `0.0.0.0:13151` | `127.0.0.1:13151`; set `OPENVM_BIND_ADDR` to change it | +| Endpoints | `POST /run_compute`, `GET /health` | The same | +| Body limit | 10 MiB | 128 MiB; set `OPENVM_MAX_REQUEST_BYTES` to change it | +| Parallel jobs | 1 | 1; set `MAX_CONCURRENT_COMPUTATIONS` to change it | +| Webhook | Up to five attempts | Up to five attempts | +| Response | `{"status":"processing","e3_id":""}` at once | + +A request is admitted before its body is read. A request over the job limit gets HTTP 429, and a +body over the limit gets HTTP 413. The webhook is retried with backoff after a network error or HTTP +5xx, 408, or 429. ### Request fields @@ -168,22 +208,19 @@ is allowed. Set `ALLOW_PRIVATE_CALLBACKS=1` to allow private addresses for local The `program` section of `interfold.config.yaml` selects the mode (`crates/config/src/program_config.rs`). -| Setting | What `interfold program start` runs | Proof | -| --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ | -| `program.dev: true` | `.interfold/support/dev/start`: the dev runner, built from your `program/` crate | Mock proof. Only a mock RISC Zero verifier accepts it. | -| `program.risc0.risc0_dev_mode: 1` | The `e3-support` container | Fake proof with an empty seal | -| `program.risc0.risc0_dev_mode: 0` | The `e3-support` container | Groth16 proof from the Boundless market | +| Setting | What `interfold program start` runs | Proof | +| -------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------- | +| `program.dev: true` | `.interfold/support/dev/start`: the dev runner, built from your `program/` crate | Mock proof. Only `MockOpenVmReceiptVerifier` accepts it. | +| `program.dev: false`, `program.openvm` | `.interfold/support/openvm/start`: the OpenVM service for your `program/` crate | OpenVM Halo2 EVM proof, verified before it is returned | -The template sets `program.dev: true`. `--dev true` on `interfold program start` or -`interfold program compile` overrides the file. When `dev` is false, `program.risc0` must be -present, or `start` fails with `start must be run with risc0 config available`. `risc0_dev_mode` -defaults to `1` when it is not set. +`--dev true` on `interfold program start` or `interfold program compile` overrides the file, as does +`E3_PROGRAM__DEV=true`. The template's local scripts set it unless `TEMPLATE_REAL_PROOFS=1`, and +CRISP's unless `CRISP_REAL_PROOFS=1`. A configuration with the removed `program.risc0` section still +loads, but `interfold program` refuses it. ## Proof format -The RISC Zero guest (`crates/support/methods/guest/src/bin/program.rs`) reads the inputs, runs the -secure process with `policy()`, and commits a nine-field journal. Each field is 32 bytes. RISC Zero -serializes them as 132 bytes each, which gives a 1188-byte journal (`lib/Risc0ComputeProof.sol`). +The guest reveals SHA-256 of nine 32-byte ABI words, 288 bytes (`lib/OpenVmComputeProof.sol`): 1. Chain ID 2. Interfold contract address @@ -195,86 +232,111 @@ serializes them as 132 bytes each, which gives a 1188-byte journal (`lib/Risc0Co 8. BFV parameter hash 9. Input root -The CP returns the proof as `abi.encode(bytes seal, bytes32 paramsHash, bytes32 inputRoot)` -(`encode_compute_proof` in `crates/support/host/src/lib.rs`). `Risc0ComputeProof.decode` reads the -same layout on-chain. The verifiers rebuild the other seven fields from on-chain state. See +The CP returns the proof as `abi.encode(bytes seal, bytes32 paramsHash, bytes32 inputRoot)`. The +seal is `abi.encode(uint8(1), bytes(halo2ProofData), bytes32[9](journalWords))`, 2,144 bytes. +`OpenVmComputeProof.decode` reads the envelope on-chain. The verifiers rebuild the other seven +fields from on-chain state. See [Verify the Compute Provider](/build/e3-program/verify-compute-provider). ## The guest must match your E3 program -The published `e3-support` image embeds the CRISP secure process from `crates/support/program`. The -guest links it as `e3-user-program` (`crates/support/methods/guest/Cargo.toml`). The container does -not mount your `program/` folder. - -- In dev mode, the dev runner builds your `program/` crate. This is the mode that the template uses. -- In RISC Zero mode, the guest runs the CRISP processor and policy. A different E3 program needs a - guest that is built against its own `e3-user-program` crate. -- A different guest has a different image ID. The protocol verifier and your program contract must - both name that image ID. +The guest and the service link your `program/` crate, so they run your processor and your policy. +The contract, the host, and the guest must derive the same leaves, the same selection, the same +parameter hash, and the same journal. -The Interfold contract keeps one ciphertext verifier for each encryption scheme, and its image ID is -immutable. On one deployment, every BFV E3 program must therefore use the guest that this verifier -names. The template deploys its own verifier for its local chain (`deploy/default.ts`). +- A changed program, policy, or `guest/openvm.toml` gives a new receipt identity: a new executable + commitment and VM commitment. The protocol verifier and your program contract must both name it, + so a changed guest needs new verifiers. +- The Interfold contract keeps one ciphertext verifier for each encryption scheme. On one + deployment, every BFV E3 program must use the receipt identity that this verifier names. The + template deploys its own verifiers for its chain (`deploy/default.ts`). +- If your program hashes data inside the guest, add the hash to the `openvm-hashes` feature of your + `program/` crate and to `guest/openvm.toml`, as CRISP does for SHA-256. ## Run a compute provider -This procedure starts the RISC Zero CP with Boundless proofs. Run it in an Interfold project that -`interfold init` made. The `interfold program` commands use the scripts in `.interfold/support/ctl`, -which `interfold init` writes. +This procedure builds and starts the OpenVM CP. Run it in an Interfold project that `interfold init` +made. - The program server does not authenticate callers. Any caller that can reach port 13151 can start a - computation that your Boundless key pays for. + The program server does not authenticate callers. Any caller that can reach the port can start a + computation that your machine proves. Keep it on loopback or behind authenticated admission + control. ### Install the tools -Install Docker and the Interfold CLI. See [Installation](/build/installation). The RISC Zero -toolchain and Foundry run inside the `e3-support` image, so the host does not need them for this -procedure. +Install the Interfold CLI (see [Installation](/build/installation)) and `cargo-openvm`: -### Configure the program section +```bash +cargo install --locked --git https://github.com/openvm-org/openvm.git --tag v2.0.2 cargo-openvm +cargo openvm setup +``` + +`cargo openvm setup` writes the Halo2 proving key, the KZG parameters, and the EVM verifier to +`~/.openvm`. Check their provenance before you use them. -Set `program.dev` to `false` and add a `program.risc0` section to `interfold.config.yaml`: +### Build the workers + +Build the worker from the Interfold repository at the same revision as your project: + +```bash +cargo build --locked --release --manifest-path crates/openvm-prover/Cargo.toml +``` + +On a machine with an NVIDIA GPU, also build the CUDA worker into its own directory. It needs the +CUDA toolkit: + +```bash +CARGO_TARGET_DIR=target/cuda cargo build --locked --release --features cuda \ + --manifest-path crates/openvm-prover/Cargo.toml +``` + +### Configure the program section ```yaml filename="interfold.config.yaml" program: dev: false - risc0: - risc0_dev_mode: 0 - boundless: - rpc_url: 'https://sepolia.base.org' - private_key: '${PRIVATE_KEY}' - pinata_jwt: '${PINATA_JWT}' - ipfs_gateway_url: 'https://your-gateway.mypinata.cloud' - onchain: true + openvm: + prover_bin: /opt/openvm/interfold-openvm-prover + prover_bin_cuda: /opt/openvm/interfold-openvm-prover-cuda + backend: auto ``` -The account of `private_key` must hold ETH on the Boundless chain for gas and for the request -payment. - -### Compile the guest +| Key | Default | Meaning | +| ----------------- | ------------------ | --------------------------------------------- | +| `prover_bin` | None | The CPU worker | +| `prover_bin_cuda` | None | The CUDA worker | +| `backend` | `auto` | `auto`, `cpu`, or `cuda` | +| `prover_config` | Written by compile | The worker configuration | +| `setup_dir` | `~/.openvm` | The directory that `cargo openvm setup` wrote | -Run `interfold program compile`. The container builds the guest ELF at -`target/riscv-guest/methods/guests/riscv32im-risc0-zkvm-elf/release/program.bin` in `/app`. On the -host, `/app/target` is `.interfold/caches/target`. +Set at least one worker. Every path is absolute. With `backend: auto` the service uses the CUDA +worker when it is set and can open a GPU, and the CPU worker otherwise. `cuda` refuses to start +without a working GPU, and `cpu` never tries one. -### Upload the guest +### Compile -Run `interfold program upload`. The script uploads the ELF to Pinata and writes the URL to -`target/.program_url`. Copy that URL to `program.risc0.boundless.program_url`. Without it, the host -uploads the ELF at run time. +Run `interfold program compile`. It builds `guest/`, generates the application proving key, runs the +worker's `prepare` for the aggregation key and the receipt identity, writes +`.interfold/caches/openvm/prover.json`, and builds the service. The keys are regenerated only when +the guest executable or `guest/openvm.toml` changes. The identity is in +`.interfold/caches/openvm/prepared/identity.json`. -### Restrict the port +### Deploy the verifiers -Allow connections to port 13151 only from your coordination server. The container publishes the port -on all host interfaces. +Deploy the contracts. The template and CRISP deploys read the identity and the verifier artifact +from `prover.json`, unless you set `OPENVM_APP_EXE_COMMIT` and `OPENVM_APP_VM_COMMIT` with either +`OPENVM_VERIFIER_ARTIFACT` and `OPENVM_VERIFIER_SHA256` or `OPENVM_HALO2_VERIFIER` and +`OPENVM_HALO2_RUNTIME_CODE_HASH`. ### Start the program server -Run `interfold program start`. The container starts `e3-support-app` on port 13151. +Run `interfold program start`. The service picks its worker and runs the worker's `check`, which +loads every key and both KZG parameter files and recomputes the receipt identity. Then it listens on +`127.0.0.1:13151`. ### Check the server @@ -282,50 +344,17 @@ Run `curl http://localhost:13151/health`. The server returns `{"status":"healthy -The container image is `ghcr.io/theinterfold/e3-support:`, where `` is the -output of `interfold rev`. The script pulls the image when it is not available locally. Set -`E3_SUPPORT_IMAGE_REPOSITORY` to use a mirror. - -## Toolchain versions - -The `e3-support` image pins its tools in `crates/support/Dockerfile`. Use the same versions when you -build `crates/support` outside the container. - -| Tool | Version | Source in the Dockerfile | -| ------------------------ | ------- | -------------------------------------- | -| Rust | 1.91.1 | Base image `rust:1.91.1-slim-bookworm` | -| RISC Zero Rust toolchain | 1.91.1 | `rzup install rust 1.91.1` | -| `r0vm` | 3.0.3 | `rzup install r0vm 3.0.3` | -| `cargo-risczero` | 3.0.3 | `rzup install cargo-risczero 3.0.3` | -| Foundry | Latest | `foundryup` | - -The Dockerfile installs `rzup` and Foundry with these commands: - -```sh -curl -L https://risczero.com/install | bash -curl -L https://foundry.paradigm.xyz | bash -``` - -The template pins Rust 1.91.1 in `rust-toolchain.toml`. The local stack of the template uses `anvil` -from Foundry. - -## Boundless offer parameters - -Each optional field under `program.risc0.boundless` goes to the container as an environment -variable. The defaults come from `crates/support/host/src/lib.rs`. +## Deadlines and memory -| Config field | Environment variable | Default | Description | -| --------------------- | ------------------------------- | --------- | ---------------------------------------------- | -| `min_price_eth` | `BOUNDLESS_MIN_PRICE_ETH` | `0.00005` | Start price of the auction, in ETH | -| `max_price_eth` | `BOUNDLESS_MAX_PRICE_ETH` | `0.004` | Highest price of the auction, in ETH | -| `timeout_secs` | `BOUNDLESS_TIMEOUT_SECS` | `28800` | Total life of the request, in seconds | -| `lock_timeout_secs` | `BOUNDLESS_LOCK_TIMEOUT_SECS` | `14400` | Deadline of the prover that locks the request | -| `ramp_up_secs` | `BOUNDLESS_RAMP_UP_SECS` | `7200` | Time for the price to go from start to highest | -| `lock_collateral_zkc` | `BOUNDLESS_LOCK_COLLATERAL_ZKC` | `100.0` | ZKC that the prover locks | +| Variable | Default | Meaning | +| ----------------------------- | ------- | -------------------------------------------------------------------- | +| `OPENVM_CHECK_TIMEOUT_SECS` | 1800 | Deadline for the startup `check` | +| `OPENVM_PROVE_TIMEOUT_SECS` | 86400 | Deadline for one proof. The worker is stopped and the round fails. | +| `OPENVM_SEGMENT_MEMORY_BYTES` | 8 GiB | Read by `compile`. The segment memory limit; 8 GiB fits a 16 GB GPU. | -The host refuses a minimum price above the maximum price. It also refuses a lock timeout of zero or -a lock timeout that is not less than the total timeout. The ramp-up period must not be longer than -the lock timeout. +The worker holds the guest's input stream in memory twice, about eight times the binary size of the +round. Jobs are in memory: a restart of the service loses accepted jobs, and the operator must +reconcile them. ## Next steps @@ -335,7 +364,7 @@ the lock timeout. href='/build/e3-program/verify-compute-provider' icon='shield' > - How the proof is checked on-chain, and how to check the image ID. + How the proof is checked on-chain, and how to check the receipt identity. See the dev runner and the webhook in one E3. diff --git a/docs/pages/build/e3-program/index.mdx b/docs/pages/build/e3-program/index.mdx index 3329a2c2d6..f52fc3862d 100644 --- a/docs/pages/build/e3-program/index.mdx +++ b/docs/pages/build/e3-program/index.mdx @@ -19,13 +19,13 @@ the end, you know which file to edit for each change and which page explains it. An E3 program has five parts. You write the secure process, the program contract, and the client and server. The compute provider and the protocol verifiers come from the Interfold repository. -| Part | What it does | Default template | CRISP example | -| ------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- | -------------------------------------------------------------------- | -| Secure process | The FHE computation. It combines encrypted inputs into one encrypted output. | `program/src/lib.rs` (`fhe_processor`, `policy`) | `examples/CRISP/program/src/lib.rs` | -| E3 program contract | Implements `IE3Program`. It accepts inputs, keeps the input tree, and verifies the output proof. | `contracts/MyProgram.sol` | `examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol` | -| Compute provider | Runs the secure process off-chain and proves the run. | `crates/support-scripts/dev` (dev mode) or `crates/support` (RISC Zero) | `crates/support` (RISC Zero with Boundless) | -| Verifiers | Check the compute proof on-chain before the Interfold contract accepts the output. | `Risc0BfvCiphertextVerifier` and the check in `MyProgram.verify` | `Risc0BfvCiphertextVerifier` and `CRISPProgram.verify` | -| Client and server | The client encrypts and submits inputs. The server starts the compute and publishes the output. | `client/src/`, `server/index.ts` | `examples/CRISP/client`, `examples/CRISP/server` | +| Part | What it does | Default template | CRISP example | +| ------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| Secure process | The FHE computation. It combines encrypted inputs into one encrypted output. | `program/src/lib.rs` (`fhe_processor`, `policy`) | `examples/CRISP/program/src/lib.rs` | +| E3 program contract | Implements `IE3Program`. It accepts inputs, keeps the input tree, and verifies the output proof. | `contracts/MyProgram.sol` | `examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol` | +| Compute provider | Runs the secure process off-chain and proves the run. | `.interfold/support/dev` (dev mode) or `.interfold/support/openvm` and `guest/` (OpenVM) | `examples/CRISP/.interfold/support/openvm` and `examples/CRISP/guest` | +| Verifiers | Check the compute proof on-chain before the Interfold contract accepts the output. | `OpenVmBfvCiphertextVerifier` and the check in `MyProgram.verify` | `OpenVmBfvCiphertextVerifier` and `CRISPProgram.verify` | +| Client and server | The client encrypts and submits inputs. The server starts the compute and publishes the output. | `client/src/`, `server/index.ts` | `examples/CRISP/client`, `examples/CRISP/server` | Template paths are relative to the project root. CRISP paths and `crates/` paths are relative to the root of the Interfold repository. @@ -85,17 +85,17 @@ committee key and decrypt the output. See [The Interfold Contract](/build/interf ## Calls between the parts -| Caller | Called contract or service | Function or endpoint | When | -| ---------------------- | ---------------------------- | --------------------------------- | ---------------------------------------- | -| Requester | Interfold contract | `request` | Once, to start the E3 | -| Interfold contract | Program contract | `validate` | Inside `request` | -| Client (data provider) | Program contract | `publishInput` | During the input window | -| Server | Compute provider | `POST /run_compute` | After the input window closes | -| Compute provider | Server | Webhook callback (`callback_url`) | When the proof is ready | -| Server | Interfold contract | `publishCiphertextOutput` | Before the compute deadline | -| Interfold contract | Program contract | `verifyDataAvailability` | Inside `publishCiphertextOutput`, first | -| Interfold contract | `Risc0BfvCiphertextVerifier` | `verify` | Inside `publishCiphertextOutput`, second | -| Interfold contract | Program contract | `verify` | Inside `publishCiphertextOutput`, third | +| Caller | Called contract or service | Function or endpoint | When | +| ---------------------- | ----------------------------- | --------------------------------- | ---------------------------------------- | +| Requester | Interfold contract | `request` | Once, to start the E3 | +| Interfold contract | Program contract | `validate` | Inside `request` | +| Client (data provider) | Program contract | `publishInput` | During the input window | +| Server | Compute provider | `POST /run_compute` | After the input window closes | +| Compute provider | Server | Webhook callback (`callback_url`) | When the proof is ready | +| Server | Interfold contract | `publishCiphertextOutput` | Before the compute deadline | +| Interfold contract | Program contract | `verifyDataAvailability` | Inside `publishCiphertextOutput`, first | +| Interfold contract | `OpenVmBfvCiphertextVerifier` | `verify` | Inside `publishCiphertextOutput`, second | +| Interfold contract | Program contract | `verify` | Inside `publishCiphertextOutput`, third | Two values connect the secure process to the program contract. The first is the input root: the compute provider and the program contract must build the same input tree from the same inputs. The @@ -127,7 +127,7 @@ guest program that the image ID names. icon='layers' tag='Off-chain' > - How the program server runs the secure process and returns a RISC Zero proof. + How the program server runs the secure process and returns an OpenVM proof. ) -> Vec` | The computation. It returns the serialized output ciphertext. | -| `policy` | `fn() -> InputPolicy` | How each input becomes a tree leaf, and which inputs to compute over. | +| Function | Type | Purpose | +| --------------- | -------------------------------------- | --------------------------------------------------------------------- | +| `fhe_processor` | `fn(FHEProcessorInput<'_>) -> Vec` | The computation. It returns the serialized output ciphertext. | +| `policy` | `fn() -> InputPolicy` | How each input becomes a tree leaf, and which inputs to compute over. | The crate is named `e3-user-program` in the template (`program/Cargo.toml`). It depends on `fhe` and -`fhe-traits` (fhe.rs, tag `v0.4.1`), `e3-compute-provider`, and `e3-fhe-params`. The dev runner and -the RISC Zero guest link a crate with this name and call these two functions. See +`fhe-traits` (fhe.rs, revision `873dc69`), `e3-compute-provider`, and `e3-fhe-params`. The dev +runner, the OpenVM service, and the OpenVM guest in `guest/` link a crate with this name and call +these two functions. See [The guest must match your E3 program](/build/e3-program/compute-provider#the-guest-must-match-your-e3-program). This is the policy and the processor of the default template @@ -42,10 +43,10 @@ pub fn policy() -> InputPolicy { InputPolicy::default() } -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -62,21 +63,24 @@ The crate defines the processor type and its input in `crates/compute-provider/src/compute_input.rs`: ```rust filename="crates/compute-provider/src/compute_input.rs" -pub type FHEProcessor = for<'a> fn(&FHEProcessorInput<'a>) -> Vec; +pub type FHEProcessor = for<'a> fn(FHEProcessorInput<'a>) -> Vec; pub struct FHEProcessorInput<'a> { - pub ciphertexts: &'a [(Vec, u64)], + pub ciphertexts: &'a mut dyn Iterator, u64)>, pub params: &'a Arc, } ``` -| Field | Content | -| ------------- | ---------------------------------------------------------------------------------------------------------------------- | -| `ciphertexts` | The serialized fhe.rs BFV ciphertexts that the policy selected, in index order. Each one has its on-chain input index. | -| `params` | The BFV parameters of the E3, decoded one time and shared with the processor. | +| Field | Content | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| `ciphertexts` | The serialized fhe.rs BFV ciphertexts that the policy selected, one at a time, in index order. Each has its on-chain input index. | +| `params` | The BFV parameters of the E3, decoded one time and shared with the processor. | -The processor receives only the inputs that the policy selected. The crate builds the input tree -from all inputs first. See [Rules the crate enforces](#rules-the-crate-enforces). +The processor receives only the inputs that the policy selected, and it must read every one. The +crate builds the input tree from all inputs first. Inside the OpenVM guest, each ciphertext is read +from the input stream and checked against the hash of its first read only when the processor asks +for it, so keep the state that the processor carries between inputs small. See +[Rules the crate enforces](#rules-the-crate-enforces). ## BFV parameters @@ -107,7 +111,7 @@ constants in `crates/fhe-params/src/constants.rs`. ## Processor output The processor returns the serialized output ciphertext (`Ciphertext::to_bytes`). The crate then -computes four values from the run (`ComputeInput::run_batched`): +computes four values from the run (`SecureProcess`, which `ComputeInput::run` also uses): | Value | How the crate computes it | | ----------------------- | ------------------------------------------------------------ | @@ -126,7 +130,7 @@ An `InputPolicy` holds two function pointers (`crates/compute-provider/src/polic ```rust filename="crates/compute-provider/src/policy.rs" pub type LeafFn = fn(&PublishedInput) -> Result; -pub type SelectFn = fn(&[PublishedInput]) -> Vec; +pub type SelectFn = fn(&[InputRecord]) -> Vec; pub struct InputPolicy { pub leaf: LeafFn, @@ -140,9 +144,14 @@ pub struct InputPolicy { - `select` returns the indices of the inputs to compute over. It must be a function of data that the input root binds. Then every prover that uses the same inputs selects the same set. -`PublishedInput` gives the policy the input `index`, the `ciphertext` bytes, the `commitment` that -the contract stored (if any), opaque `metadata`, and `recomputed`. The `recomputed` field is the -commitment that the crate computes from the bytes. It is `None` when the bytes do not deserialize. +`PublishedInput` gives the leaf function the input `index`, the `ciphertext` bytes and their +Keccak-256 `ciphertext_hash`, the `commitment` that the contract stored (if any), opaque `metadata`, +and `recomputed`. The `recomputed` field is the commitment that the crate computes from the bytes. +It is `None` when the bytes do not deserialize. + +`select` receives an `InputRecord` for each input: the same fields without the ciphertext bytes. The +secure process reads each ciphertext once for its leaf and does not keep it, so selection works on +what remains. Both types have `matches_commitment()`. ### Default policy @@ -164,10 +173,10 @@ pub fn leaf(input: &PublishedInput) -> Result { index: input.index, reason: "CRISP publishes a commitment with every input".to_string(), })?; - metadata_of(input)?; + metadata_of(input.index, input.metadata)?; let mut outer = Sha256::new(); - outer.update(Keccak256::digest(input.ciphertext)); + outer.update(input.ciphertext_hash.as_slice()); outer.update(commitment); outer.update(input.metadata); Ok(leaf_from_digest(&outer.finalize())) @@ -196,6 +205,9 @@ The crate applies these rules for every E3 program. A policy cannot change them. has no field for a root or for leaves. - Every published input gets a leaf, also when `select` does not choose it. - A selected index outside the input list stops the run with `ComputeError::MerkleTree`. +- A selected ciphertext that differs from its first read stops the run with + `ComputeError::InputChanged`, and a processor that returns before it reads every selected input + stops it with `ComputeError::Unread`. - When the program publishes per-input data, the list must have one entry for each ciphertext. Otherwise the run stops with `ComputeError::MerkleTree`. @@ -212,7 +224,7 @@ The processor has no secret key. It cannot read the value of a ciphertext, so it encrypted data. Control flow can use only public data, for example the number of inputs, their indices, and the parameters. -| Operation (fhe.rs `v0.4.1`) | Result | +| Operation (fhe.rs `873dc69`) | Result | | --------------------------------------------- | --------------------------------------------------- | | Ciphertext plus or minus ciphertext, negation | Two components. The output can be published. | | Ciphertext plus, minus, or times plaintext | Two components. The output can be published. | @@ -231,8 +243,9 @@ Other limits: panic stops the guest, and the E3 gets no output. - When `select` returns no inputs, `Ciphertext::zero` has no components. The output commitment then rejects the output. -- The zkVM guest is single threaded. Each input adds cycles to the proof, so large rounds take more - time and cost more on Boundless. +- The zkVM guest is single threaded. Each input adds cycles to the proof, so large rounds take + longer to prove. The guest holds one ciphertext at a time, so its memory does not limit the number + of inputs. ## Test the processor @@ -252,7 +265,7 @@ the computation. Insert the same leaf on-chain that your policy builds off-chain. - Run the secure process in dev mode or in the RISC Zero zkVM. + Run the secure process in dev mode or in the OpenVM zkVM. Follow one E3 through the template from request to result. diff --git a/docs/pages/build/e3-program/verify-compute-provider.mdx b/docs/pages/build/e3-program/verify-compute-provider.mdx index 0c8b3c6a09..231b2839f4 100644 --- a/docs/pages/build/e3-program/verify-compute-provider.mdx +++ b/docs/pages/build/e3-program/verify-compute-provider.mdx @@ -1,7 +1,7 @@ --- title: 'Verify the Compute Provider' description: - 'How the Interfold contract checks a RISC Zero compute proof, what each check binds, and how to + 'How the Interfold contract checks an OpenVM compute proof, what each check binds, and how to confirm that a deployed verifier accepts the guest built from a given source.' --- @@ -10,10 +10,10 @@ import { LinkCard, LinkCards } from '@/components/ui' # Verify the Compute Provider -A RISC Zero proof shows which guest program ran and what it committed. This page explains how the -Interfold contract checks that proof, which values each check binds, and how to confirm the image ID +An OpenVM proof shows which guest ran and what it revealed. This page explains how the Interfold +contract checks that proof, which values each check binds, and how to confirm the receipt identity of a deployment. It is for E3 program developers, auditors, and operators who did not build the -deployment. At the end, you can tie a deployed verifier to a source commit. +deployment. At the end, you can tie a deployed verifier to a guest and its source. ## Two checks on one proof @@ -21,7 +21,7 @@ deployment. At the end, you can tie a deployed verifier to a source commit. (`InterfoldLifecycle.publishCiphertext` and `_isValidCiphertextHash`): 1. The protocol ciphertext verifier of the encryption scheme. For BFV this is - `Risc0BfvCiphertextVerifier` (`contracts/verifiers/bfv/Risc0BfvCiphertextVerifier.sol`). + `OpenVmBfvCiphertextVerifier` (`contracts/verifiers/bfv/OpenVmBfvCiphertextVerifier.sol`). 2. `verify` on the program contract of the E3. Before these checks, the Interfold contract calls `verifyDataAvailability` on the program contract. @@ -29,21 +29,24 @@ If a verifier returns `false`, the call reverts with `InvalidOutput`. After the Interfold contract reads the stage again and checks committee viability again. Then it stores the output hash and commitment and moves the E3 to `CiphertextReady`. -Both verifiers rebuild the same journal and call the RISC Zero verifier: +Both verifiers rebuild the same journal and call the same `OpenVmReceiptVerifier`: ```solidity -risc0Verifier.verify(proof.seal, imageId, sha256(journal)); +openVmVerifier.verify(proof.seal, imageId, sha256(journal)); ``` -The RISC Zero verifier reverts when the seal does not prove that the guest with `imageId` committed -that journal. +`OpenVmReceiptVerifier` (`contracts/verifiers/OpenVmReceiptVerifier.sol`) checks that `imageId` is +its own identity, decodes the seal, checks that the nine journal words in the seal hash to the +expected digest, and calls the Halo2 verifier with the digest as the public values and its two +application commitments. The Halo2 verifier reverts when the proof does not show that the guest with +those commitments revealed that digest. ## What each check binds -The journal has nine 32-byte fields (`lib/Risc0ComputeProof.sol`). The table shows where each -verifier gets each field. A call argument is a value from the caller of `publishCiphertextOutput`. +The journal has nine 32-byte words (`lib/OpenVmComputeProof.sol`). The table shows where each +verifier gets each word. A call argument is a value from the caller of `publishCiphertextOutput`. -| Field | `Risc0BfvCiphertextVerifier` | `MyProgram.verify` (template) | +| Word | `OpenVmBfvCiphertextVerifier` | `MyProgram.verify` (template) | | ------------------------- | ------------------------------------------ | -------------------------------------------------------- | | Chain ID | `block.chainid` | `block.chainid` | | Interfold contract | `msg.sender` (the Interfold proxy) | `address(interfold)` | @@ -57,7 +60,7 @@ verifier gets each field. A call argument is a value from the caller of `publish The caller supplies the output hash and the commitment, and the Interfold contract stores them in the E3. The proof binds them to this chain, this Interfold contract, this E3, this committee key, -and these parameters. The prover cannot change these other fields. +and these parameters. The prover cannot change these other words. The protocol verifier does not check the input root. The program contract must compare the input @@ -66,34 +69,44 @@ and these parameters. The prover cannot change these other fields. this comparison. -The guest derives the input root from the ciphertexts it processes. `ComputeInput` has no root field -(`crates/compute-provider/src/compute_input.rs`). The root in the journal is therefore a function of -the inputs that the output used. +The guest derives the input root from the ciphertexts it reads. Its input has no root field +(`e3_openvm_types::GuestHeader`), and every ciphertext contributes a leaf whatever the policy +selects. The root in the journal is therefore a function of the inputs that the output used. -## The verifier is fixed for each E3 +## The receipt identity + +`OpenVmReceiptVerifier` binds three values, all `immutable` and `public`: + +- `verifier`: the Halo2 verifier contract; +- `appExeCommit`: the commitment of the guest executable; +- `appVmCommit`: the commitment of the VM configuration (`guest/openvm.toml`). + +Its `imageId` is +`keccak256(abi.encode(keccak256("INTERFOLD_OPENVM_RECEIPT_V1"), verifier, appExeCommit, appVmCommit))`. +The protocol verifier and the program contract must both name this `imageId`. The constructor +refuses a verifier address with no code and a commitment that is zero or not a canonical BN254 +scalar. These properties hold without any action from you: - **The verifier is fixed at request time.** `bindCryptoConfig` copies the current ciphertext verifier of the scheme and the parameter hash into a per-E3 record. A later `setCiphertextVerifier` changes only future requests. -- **The image ID cannot change.** `Risc0BfvCiphertextVerifier.imageId` and `risc0Verifier` are - `immutable` and `public`. The constructor refuses a zero image ID and a verifier address with no - code. +- **The identity cannot change.** `OpenVmBfvCiphertextVerifier.imageId` and `openVmVerifier` are + `immutable`. A rebuilt guest needs new verifiers. - **One verifier for each scheme.** The Interfold contract keeps one current ciphertext verifier for - each encryption scheme. Every BFV E3 program on a deployment must use the guest that it names. + each encryption scheme. Every BFV E3 program on a deployment must use the identity that it names. -An E3 program can keep its own image ID and RISC Zero verifier. The template sets them in the -constructor and has no setter. `CRISPProgram` has `setImageId` and `setRisc0Verifier`, which only +An E3 program can keep its own identity and receipt verifier. The template sets them in the +constructor and has no setter. `CRISPProgram` has `setImageId` and `setOpenVmVerifier`, which only its owner can call. A change to these values cannot replace an output that the Interfold contract already accepted. It can make an E3 in progress fail, because `verify` then checks the proof against -a different guest. +a different identity. ## Check a deployment -Use this procedure to compare a deployed verifier with the released source. You need Foundry -(`cast`), an RPC URL, and the Interfold contract address from -[Contract Addresses](/reference/contracts). +Use this procedure to compare a deployed verifier with a guest. You need Foundry (`cast`), an RPC +URL, and the Interfold contract address from [Contract Addresses](/reference/contracts). @@ -106,37 +119,34 @@ cast call "getCiphertextVerifier(bytes32)(address)" \ The result is the ciphertext verifier for new BFV requests. -### Read the image ID +### Read the identity ```bash cast call "imageId()(bytes32)" --rpc-url +cast call "openVmVerifier()(address)" --rpc-url +cast call "appExeCommit()(bytes32)" --rpc-url +cast call "appVmCommit()(bytes32)" --rpc-url +cast call "verifier()(address)" --rpc-url ``` -### Read the RISC Zero verifier - -```bash -cast call "risc0Verifier()(address)" --rpc-url -``` +### Compare with the guest -Make sure that this address is the RISC Zero verifier that you expect for this chain. - -### Compare with the source - -Open `crates/support/contracts/ImageID.sol` at the release tag. Compare `PROGRAM_ID` with the image -ID from the chain. The two values must be equal. If they are different, the deployment does not -match this source. +Build the guest from the source you trust with `interfold program compile` in its project. Compare +`app_exe_commit` and `app_vm_commit` in `.interfold/caches/openvm/prepared/identity.json` with the +two commitments from the chain. The values must be equal. ### Check the program contract Read `imageId()` on the program contract. Read `verifier()` on a template program or -`risc0Verifier()` on `CRISPProgram`. Compare them with the values from the previous steps. +`openVmVerifier()` on `CRISPProgram`. Compare them with the values from the previous steps. ### Generate the provenance manifest From the repository root, run: ```bash -pnpm provenance:manifest --rpc --verifier --out manifest.json +pnpm provenance:manifest --config --prover \ + --rpc --verifier --out manifest.json ``` Make sure that the manifest shows `"complete": true`. The `unresolved` list names each field that @@ -146,41 +156,28 @@ the script did not resolve. The manifest (`scripts/generate-provenance-manifest.ts`) records these values: -- The source commit, and whether the working tree is clean -- The RISC Zero version, the guest toolchain, the host toolchain, and the guest builder image tag - and digest -- The Interfold revision pins of the guest workspace, and the digests of the two lockfiles -- The guest ELF path and SHA-256, and the image ID from `ImageID.sol` -- The chain ID, the verifier address and the SHA-256 of its code, the RISC Zero verifier address, - and the on-chain image ID - -The manifest is `complete: false` when a field is missing, or when the on-chain image ID is not -equal to `ImageID.sol`. An incomplete manifest records an unfinished check. It is not a passing -result. - -## Reproduce the image ID from source - -The manifest compares the chain with the committed `ImageID.sol`. It does not rebuild the guest. To -check that `ImageID.sol` matches the source, rebuild the guest in the pinned Docker builder. +- The source commit, whether the working tree is clean, and the digests of CRISP's lockfiles, the + guest lockfile, the worker lockfile, and the guest's `openvm.toml` +- The SHA-256 of the application key, the executable, the aggregation key, the Halo2 key, the + verifier artifact, the Halo2 parameter files, and the worker +- The two application commitments, and whether the worker's `check` passed +- The chain ID, the three verifier addresses and the hashes of their code, and whether the deployed + identity and Halo2 runtime match the configured guest and artifact -1. Check out the release tag. -2. Go to `crates/support`. -3. Run `RISC0_USE_DOCKER=1 cargo build --locked -p methods`. -4. Run `git diff contracts/ImageID.sol`. The diff must be empty. +The manifest is `complete: false` when a field is missing. An incomplete manifest records an +unfinished check. It is not a passing result. -Only the Docker build writes `ImageID.sol` (`crates/support/methods/build.rs`). A native build can -give a different image ID on a different toolchain, so the build script skips the Solidity output -for it. +## Reproduce the identity from source -The guest reads `e3-compute-provider` and `e3-fhe-params` through git revision pins. Three pins must -name the same revision: `e3-fhe-params` and `e3-compute-provider` in `crates/support/Cargo.toml`, -and `e3-compute-provider` in `crates/support/methods/guest/Cargo.toml`. A new revision gives a new -image ID, so a guest change needs a new `Risc0BfvCiphertextVerifier`. +The manifest checks artifacts and the chain against each other. It does not rebuild the guest. To +check the commitments against the source, rebuild the guest from a clean checkout with the pinned +toolchains: `cargo-openvm` v2.0.2, its guest toolchain, and the guest's `Cargo.lock` +(`OPENVM_BUILD_LOCKED=1`). Then run the worker's `prepare` and compare the new `identity.json`. - The SHA-256 of the ELF is not the image ID. SHA-256 checks that a file arrived intact. The RISC - Zero image ID comes from the loaded memory image. The manifest records both values for these two - different purposes. + The SHA-256 of the executable is not the executable commitment. SHA-256 checks that a file arrived + intact. The OpenVM commitment comes from the program's memory image and the VM. The manifest + records both values for these two different purposes. ## Limits of these checks @@ -190,8 +187,10 @@ image ID, so a guest change needs a new `Risc0BfvCiphertextVerifier`. That control belongs to [governance](/governance). - **Program values.** The protocol verifier and each program contract keep separate values. The procedure above reads both. -- **Local mocks.** The template deploys `MockRISC0Verifier`, which accepts every seal. Its dev - runner returns a placeholder seal. A local E3 therefore proves nothing about the computation. +- **Local mocks.** With `TEMPLATE_UNPROVED_TEST=1` (or `CRISP_UNPROVED_TEST=1`) on the local chain, + the deploy uses `MockOpenVmReceiptVerifier`, which accepts every seal, and the dev runner returns + a placeholder seal. Such an E3 proves nothing about the computation. +- **Audit.** The compute path and the OpenVM verifier integration are not audited. ## Next steps diff --git a/docs/pages/build/hello-world.mdx b/docs/pages/build/hello-world.mdx index db10a3c52c..02fa5b1923 100644 --- a/docs/pages/build/hello-world.mdx +++ b/docs/pages/build/hello-world.mdx @@ -63,10 +63,10 @@ pub fn policy() -> InputPolicy { } /// Implementation of the CiphertextProcessor function -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -74,7 +74,7 @@ pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { } ``` -- `FHEProcessorInput` has two fields. `ciphertexts` is a slice of `(Vec, u64)` pairs: the +- `FHEProcessorInput` has two fields. `ciphertexts` yields `(Vec, u64)` pairs one at a time: the serialized ciphertext and its input index. `params` holds the BFV parameters of the E3. - `Ciphertext::zero` makes the zero ciphertext, the start value. The `+=` operator adds each input ciphertext to it. This addition is homomorphic: the function adds the hidden values, but it cannot @@ -101,10 +101,10 @@ In `program/src/lib.rs`, replace the `fhe_processor` function with this version: ```rust filename="program/src/lib.rs" {9-11} /// Implementation of the CiphertextProcessor function -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -201,9 +201,10 @@ The input step shows `Ready to compute: 2 × (5 + 3) = ?`. The results step show In dev mode, the program server runs `fhe_processor` without a proof, and the template deploys - `MockRISC0Verifier`, which accepts any RISC Zero seal. With a real verifier, `MyProgram.verify` - checks the proof against the `imageId` that `MyProgram` receives when it is deployed. A change to - the program changes that image ID. See [Compute provider](/build/e3-program/compute-provider). + `MockOpenVmReceiptVerifier`, which accepts every receipt on the local chain. With real proofs, + `MyProgram.verify` checks the OpenVM receipt against the `imageId` that `MyProgram` receives when + it is deployed. A change to the program changes that identity, so compile and deploy again. See + [Compute provider](/build/e3-program/compute-provider). ## Update the integration test @@ -221,8 +222,8 @@ Run the test with `pnpm test:integration`. This test needs a CLI that is built w ## Operations on ciphertexts -The template uses the `fhe` crate from `gnosisguild/fhe.rs` at tag `v0.4.1`. For a `Ciphertext`, -that crate implements these operators: +The template uses the `fhe` crate from `gnosisguild/fhe.rs` at revision `873dc69`. For a +`Ciphertext`, that crate implements these operators: | Operation | Operator | Example | | --------------------------- | -------------------- | ----------------- | diff --git a/docs/pages/build/installation.mdx b/docs/pages/build/installation.mdx index 95b5195c54..6b75c1775a 100644 --- a/docs/pages/build/installation.mdx +++ b/docs/pages/build/installation.mdx @@ -34,29 +34,30 @@ Intel. On these platforms, [build the CLI from source](#install-the-cli). `interfold init` needs Git and pnpm. The default project template also starts a local chain, compiles Rust code, and runs a web client, so it needs more tools. -| Tool | Version | The template uses it to | -| ------------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------- | -| [Git](https://git-scm.com/downloads) | Any recent version | Clone the template, make the project repository, and add the `lib/risc0-ethereum` submodule. | -| [Node.js](https://nodejs.org/en/download) | 22 | Run the client, the coordination server, and Hardhat. The repository CI uses Node.js 22. | -| [pnpm](https://pnpm.io) | 10.7.1 | Install packages and run scripts. The `packageManager` field in `package.json` pins 10.7.1. | -| [Rust](https://rust-lang.org/tools/install/) (with `rustup`) | 1.91.1 | Build and run the program server. `rust-toolchain.toml` in the template pins this version. | -| [Foundry](https://github.com/foundry-rs/foundry) | Current release | Run `anvil`, the local chain that `pnpm dev:all` starts on port 8545. | -| A browser wallet, for example [MetaMask](https://metamask.io) | Any | Sign the transactions that the client sends to the local chain. | +| Tool | Version | The template uses it to | +| ------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------- | +| [Git](https://git-scm.com/downloads) | Any recent version | Clone the template and make the project repository. | +| [Node.js](https://nodejs.org/en/download) | 22 | Run the client, the coordination server, and Hardhat. The repository CI uses Node.js 22. | +| [pnpm](https://pnpm.io) | 10.7.1 | Install packages and run scripts. The `packageManager` field in `package.json` pins 10.7.1. | +| [Rust](https://rust-lang.org/tools/install/) (with `rustup`) | 1.91.1 | Build and run the program server. `rust-toolchain.toml` in the template pins this version. | +| [Foundry](https://github.com/foundry-rs/foundry) | Current release | Run `anvil`, the local chain that `pnpm dev:all` starts on port 8545. | +| A browser wallet, for example [MetaMask](https://metamask.io) | Any | Sign the transactions that the client sends to the local chain. | Some tools are necessary only for specific tasks. -| Tool | When you need it | -| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -| [Docker](https://docs.docker.com/get-docker/) | RISC Zero mode (`program.dev: false`) and `interfold program shell`. Both run the `e3-support` image. | -| [tmux](https://github.com/tmux/tmux/wiki/Installing) | `pnpm dev:all --tmux`, which opens each process in its own tmux pane. | -| [Noir](https://noir-lang.org/docs) (`nargo`) | Only to write your own circuits. The repository CI uses `v1.0.0-beta.26`. See [Noir circuits](/build/noir-circuits). | +| Tool | When you need it | +| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`cargo-openvm`](https://docs.openvm.dev) v2.0.2 | Real proofs (`program.dev: false`). `interfold program compile` builds the guest with it. See [Compute provider](/build/e3-program/compute-provider#run-a-compute-provider). | +| The CUDA toolkit and an NVIDIA GPU | Optional. The CUDA build of the OpenVM worker proves on the GPU; without it, the CPU worker proves. | +| [tmux](https://github.com/tmux/tmux/wiki/Installing) | `pnpm dev:all --tmux`, which opens each process in its own tmux pane. | +| [Noir](https://noir-lang.org/docs) (`nargo`) | Only to write your own circuits. The repository CI uses `v1.0.0-beta.26`. See [Noir circuits](/build/noir-circuits). | You do not install these components yourself: - **Barretenberg (`bb`) and the protocol circuits.** `interfold noir setup` downloads `bb` 5.1.0 and the circuits for release 0.18.0. The template scripts run this command for you. -- **The RISC Zero toolchain.** The `e3-support` Docker image contains it. The template runs in dev - mode by default, so it does not use RISC Zero. +- **The OpenVM guest toolchain.** `cargo-openvm` installs the toolchain it needs. The local scripts + run in dev mode by default, so they do not use OpenVM. When you run `cargo` in a folder that has a `rust-toolchain.toml` file, `rustup` uses the Rust diff --git a/docs/pages/build/project-template.mdx b/docs/pages/build/project-template.mdx index e87223be4c..6d4ec32e4b 100644 --- a/docs/pages/build/project-template.mdx +++ b/docs/pages/build/project-template.mdx @@ -35,16 +35,15 @@ does these operations in sequence: 1. It makes a shallow clone of the repository in `/tmp/__interfold-tmp-folder.1`. 2. It copies the template to the project folder. In each `package.json`, it replaces the workspace versions of `@interfold/contracts`, `@interfold/react`, and `@interfold/sdk` with the versions of - the cloned release. In `Cargo.toml`, it replaces the path dependencies `e3-program-server`, - `e3-bfv-client`, `e3-fhe-params`, and `e3-compute-provider` with Git dependencies at the cloned - commit. -3. It empties `.interfold/` except `.interfold/generated/`. Then it copies the support scripts from - `crates/support-scripts/ctl` and `crates/support-scripts/dev` to `.interfold/support/`. + the cloned release. In each `Cargo.toml`, including the guest's, it replaces every path + dependency on an Interfold crate (`e3-program-server`, `e3-bfv-client`, `e3-fhe-params`, + `e3-compute-provider`, `e3-openvm-host`, `e3-openvm-types`, and `e3-safe`) with a Git dependency + at the cloned commit. +3. It empties `.interfold/` except `.interfold/generated/`. Then it copies the support folders + `crates/support-scripts/dev` and `crates/support-scripts/openvm` to `.interfold/support/`. 4. It replaces `.gitignore` with `.gitignore.bak`, renames `pnpm-workspace.yaml.bak` to `pnpm-workspace.yaml`, and deletes `lib/`. -5. It runs `git init` and adds `https://github.com/gnosisguild/risc0-ethereum` as the submodule - `lib/risc0-ethereum`. It also adds `"@risc0/ethereum": "file:lib/risc0-ethereum"` to the - `devDependencies`. +5. It runs `git init`. 6. It runs `pnpm install`, unless you give `--skip-install`. 7. It commits all files with the message `Initial Commit`. @@ -57,14 +56,13 @@ in a parent folder, or in the default configuration folder. In that case, it sto - - - - - - + + + + + @@ -96,15 +94,19 @@ in a parent folder, or in the default configuration folder. In that case, it sto - + - - + + + + + + @@ -117,6 +119,7 @@ in a parent folder, or in the default configuration folder. In that case, it sto + @@ -154,28 +157,28 @@ in a parent folder, or in the default configuration folder. In that case, it sto -| Path | Contents | -| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `program/` | The Rust crate `e3-user-program`. `src/lib.rs` exports `fhe_processor` (the FHE computation) and `policy` (the input policy). | -| `contracts/` | `MyProgram.sol`, the E3 program contract, and `Mocks/MockRISC0Verifier.sol`, a verifier that accepts any RISC Zero seal. | -| `deploy/default.ts` | `deployTemplate`, which deploys the verifier, `ImageID`, and `MyProgram`, registers `MyProgram` on the Interfold contract, and writes the addresses to the config. | -| `scripts/` | The shell scripts behind the `dev:*` scripts, the local deploy entry point `deploy-local.ts`, and `anvil-automine.mjs`. | -| `server/` | The coordination server (`index.ts`) and the client for the program server (`runner.ts`). | -| `client/` | The React and Vite web client. It is the only package in `pnpm-workspace.yaml`. | -| `tests/` | The end-to-end test `integration.spec.ts` and its Anvil helpers. | -| `lib/risc0-ethereum` | The Git submodule with the RISC Zero Solidity contracts. `remappings.txt` maps `risc0/` to it. | -| `.interfold/generated/` | Generated files. `contracts/ImageID.sol` holds the program image ID. Hardhat compiles this folder together with `contracts/`. | -| `.interfold/support/` | The support scripts that `interfold program` runs. `dev/` holds the dev-mode program server crate. `ctl/` holds the Docker scripts for RISC Zero mode. | -| `Cargo.toml` | The Cargo workspace. Its members are `program` and `.interfold/support/dev`. | -| `deployed_contracts.json` | The deployment records that the deploy scripts read and write. | -| `flake.nix` | A Nix development shell with Rust 1.91.1, Node.js, and pnpm. `.envrc` loads it with direnv. | +| Path | Contents | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `program/` | The Rust crate `e3-user-program`. `src/lib.rs` exports `fhe_processor` (the FHE computation) and `policy` (the input policy). | +| `guest/` | The OpenVM guest that proves `program/`. A Cargo workspace of its own; `openvm.toml` lists the VM extensions. | +| `contracts/` | `MyProgram.sol`, the E3 program contract, and `Mocks/MockOpenVmReceiptVerifier.sol`, a verifier that accepts every receipt, for the local chain only. | +| `deploy/default.ts` | `deployTemplate`, which deploys the receipt verifier and `MyProgram`, registers `MyProgram` on the Interfold contract, and writes the addresses to the config. | +| `scripts/` | The shell scripts behind the `dev:*` scripts, the local deploy entry point `deploy-local.ts`, and `anvil-automine.mjs`. | +| `server/` | The coordination server (`index.ts`) and the client for the program server (`runner.ts`). | +| `client/` | The React and Vite web client. It is the only package in `pnpm-workspace.yaml`. | +| `tests/` | The end-to-end test `integration.spec.ts` and its Anvil helpers. | +| `.interfold/support/` | The support folders that `interfold program` runs. `dev/` holds the development runner. `openvm/` holds the OpenVM proving service and its `compile` and `start` scripts. | +| `Cargo.toml` | The Cargo workspace. Its members are `program`, `.interfold/support/dev`, and `.interfold/support/openvm/service`. | +| `deployed_contracts.json` | The deployment records that the deploy scripts read and write. | +| `flake.nix` | A Nix development shell with Rust 1.91.1, Node.js, and pnpm. `.envrc` loads it with direnv. | The scripts make more folders when they run: - `.interfold/config/` and `.interfold/data/`: the ciphernode keys and databases. - `.interfold/noir/`: `bb` and the circuits that `interfold noir setup` installs. - `.interfold/data-availability/`: the output ciphertexts that the coordination server serves. -- `.interfold/caches/`: the build caches of the RISC Zero container. +- `.interfold/caches/openvm/`: the guest build, its proving keys, the receipt identity, and the + worker configuration that `interfold program compile` writes. - `types/`, `artifacts/`, and `cache/`: the Hardhat and TypeChain output. - `target/`: the Cargo output. @@ -187,24 +190,24 @@ The `.gitignore` of the project ignores `.interfold/`, `artifacts/`, `cache/`, ` `package.json` in the project root defines these scripts. Run a script with `pnpm run `, for example `pnpm run dev:all`. The other pages use the short form, for example `pnpm dev:all`. -| Script | Command | What it does | -| ------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `dev:all` | `./scripts/dev_all.sh` | Starts the full local stack. See [What runs](/build/quick-start#what-runs). With `--tmux`, it runs `scripts/dev_all_tmux.sh` instead. | -| `predev:all` | `interfold program compile` if `ImageID.sol` is missing | Runs automatically before `dev:all`. | -| `dev:setup` | `bash ./scripts/setup.sh` | Runs `pnpm install --frozen-lockfile`, `cargo build`, `pnpm compile`, and `interfold noir setup`. It runs `interfold program compile` if `ImageID.sol` is missing. It stops if no `interfold` CLI is installed. Inside an Interfold repository checkout, it also builds the circuits and installs the CLI from source. | -| `dev:evm` | `hardhat node` | Starts a Hardhat node on port 8545. `dev:all` uses Anvil instead. Only the tmux mode uses this script. | -| `dev:ciphernodes` | `./scripts/dev_ciphernodes.sh` | Waits for the chain. Sets the ciphernode wallets, runs `interfold noir setup`, deploys the contracts, starts the five nodes, and registers them. | -| `dev:server` | `./scripts/dev_server.sh` | Waits for the ciphernodes, sets the server environment, and starts `server/index.ts` with `tsx`. | -| `dev:program` | `./scripts/dev_program.sh` | Waits for the ciphernodes and runs `interfold program start`. | -| `dev:frontend` | `./scripts/dev_frontend.sh` | Waits for the chain and the program server. Exports the `VITE_` variables and starts the client on port 3000. | -| `compile` | `hardhat compile` | Compiles the Solidity contracts and generates the TypeChain types in `types/`. | -| `deploy` | `pnpm clean:deployments && hardhat run scripts/deploy-local.ts --network localhost` | Deletes the local deployment records, then deploys the protocol and `MyProgram` to `localhost`. Run it with `pnpm run deploy`, because `pnpm deploy` is a built-in pnpm command. | -| `deploy:dev` | `hardhat run scripts/deploy-local.ts --network localhost` | Deploys the protocol and `MyProgram` to `localhost`. It does not run `clean:deployments` first. | -| `clean:deployments` | `hardhat utils:clean-deployments` | Deletes the deployment records for a network. The default network is `localhost`. | -| `lint` | `eslint .` | Runs ESLint. | -| `test` | `hardhat test` | Runs the Hardhat test runner. | -| `test:server` | `vitest run ./server/runner.test.ts` | Runs the unit tests of the program server client. | -| `test:integration` | `pnpm test:server && ./scripts/test_integration.sh` | Runs the server tests, then starts the stack and runs `tests/integration.spec.ts`. It needs a CLI built with the `test-only-skip-proof-aggregation` feature. | +| Script | Command | What it does | +| ------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dev:all` | `./scripts/dev_all.sh` | Starts the full local stack. See [What runs](/build/quick-start#what-runs). With `--tmux`, it runs `scripts/dev_all_tmux.sh` instead. | +| `predev:all` | `./scripts/compile_program.sh` | Runs `interfold program compile` with the local settings, before `dev:all`. | +| `dev:setup` | `bash ./scripts/setup.sh` | Runs `pnpm install --frozen-lockfile`, `cargo build`, `interfold program compile`, `pnpm compile`, and `interfold noir setup`. It stops if no `interfold` CLI is installed. Inside an Interfold repository checkout, it also builds the circuits and installs the CLI from source. | +| `dev:evm` | `hardhat node` | Starts a Hardhat node on port 8545. `dev:all` uses Anvil instead. Only the tmux mode uses this script. | +| `dev:ciphernodes` | `./scripts/dev_ciphernodes.sh` | Waits for the chain. Sets the ciphernode wallets, runs `interfold noir setup`, deploys the contracts, starts the five nodes, and registers them. | +| `dev:server` | `./scripts/dev_server.sh` | Waits for the ciphernodes, sets the server environment, and starts `server/index.ts` with `tsx`. | +| `dev:program` | `./scripts/dev_program.sh` | Waits for the ciphernodes and runs `interfold program start`. | +| `dev:frontend` | `./scripts/dev_frontend.sh` | Waits for the chain and the program server. Exports the `VITE_` variables and starts the client on port 3000. | +| `compile` | `hardhat compile` | Compiles the Solidity contracts and generates the TypeChain types in `types/`. | +| `deploy` | `pnpm clean:deployments && hardhat run scripts/deploy-local.ts --network localhost` | Deletes the local deployment records, then deploys the protocol and `MyProgram` to `localhost`. Run it with `pnpm run deploy`, because `pnpm deploy` is a built-in pnpm command. | +| `deploy:dev` | `hardhat run scripts/deploy-local.ts --network localhost` | Deploys the protocol and `MyProgram` to `localhost`. It does not run `clean:deployments` first. | +| `clean:deployments` | `hardhat utils:clean-deployments` | Deletes the deployment records for a network. The default network is `localhost`. | +| `lint` | `eslint .` | Runs ESLint. | +| `test` | `hardhat test` | Runs the Hardhat test runner. | +| `test:server` | `vitest run ./server/runner.test.ts` | Runs the unit tests of the program server client. | +| `test:integration` | `pnpm test:server && ./scripts/test_integration.sh` | Runs the server tests, then starts the stack and runs `tests/integration.spec.ts`. It needs a CLI built with the `test-only-skip-proof-aggregation` feature. | The client package (`client/package.json`) has its own scripts: `dev` (`vite --no-open --host`), `build`, `preview`, `format`, and `format:check`. @@ -235,7 +238,7 @@ chains: # ciphernode_registry, bonding_registry, slashing_manager, and fee_token # have the same two keys. program: - dev: true + dev: false nodes: cn1: address: '' @@ -262,8 +265,8 @@ nodes: | `chains[].data_availability.mode` | `mock_http` | Where nodes fetch the output ciphertext. `mock_http` reads it from a local HTTP service. The other mode is `avail`. | | `chains[].data_availability.rpc_url` | `http://127.0.0.1:8080/availability` | The coordination server. It serves each object at `/availability/objects/`. | | `chains[].contracts.` | `address`, `deploy_block` | The contract address and the block to read events from. `deploy/default.ts` writes these values for the contracts that it deploys. | -| `program.dev` | `true` | Dev mode. `interfold program compile` and `interfold program start` build and run the program server natively, without a zkVM proof. The default is `false`. | -| `program.risc0` | Commented out | RISC Zero settings for `dev: false`: `risc0_dev_mode` (default 1) and an optional `boundless` block. `interfold program start` needs this block when `dev` is `false`. | +| `program.dev` | `false` | `false` proves with OpenVM. `true` runs the development runner natively, without a proof. The local scripts set `E3_PROGRAM__DEV=true` unless `TEMPLATE_REAL_PROOFS=1`. | +| `program.openvm` | Commented out | The OpenVM workers and backend for `dev: false`. See [Compute Provider](/build/e3-program/compute-provider#run-a-compute-provider). | | `nodes..address` | Anvil accounts 1 to 5 | The Ethereum address of the ciphernode. | | `nodes..quic_port` | 9201 to 9205 | The QUIC port for peer-to-peer traffic. | | `nodes..ctrl_port` | 50501 to 50505 | The port of the control socket that the CLI uses to talk to a running node. | @@ -272,8 +275,10 @@ nodes: | `nodes..dashboard_port` | `8004` (`cn1` only) | Serves the node dashboard at `http://127.0.0.1:8004`. | `interfold program compile` and `interfold program start` also accept `--dev true` or `--dev false`. -The flag overrides `program.dev` for that one command. `scripts/dev_program.sh` gives no flag, so -`pnpm dev:program` uses the value in this file. +The flag overrides `program.dev` for that one command. The local scripts load +`scripts/lib/dev_config.sh`, which sets `E3_PROGRAM__DEV=true` and `TEMPLATE_UNPROVED_TEST=1` unless +`TEMPLATE_REAL_PROOFS=1`. `TEMPLATE_UNPROVED_TEST=1` makes `deployTemplate` deploy +`MockOpenVmReceiptVerifier`, and it works only on chain ID 31337. The CLI keeps the node data next to this file: keys in `.interfold/config/`, databases in `.interfold/data/`, and the prover files in `.interfold/noir/`. An environment variable with @@ -336,7 +341,8 @@ when the template is inside an Interfold repository checkout, where the scripts | How the client shows the result | `client/src/pages/steps/EncryptSubmit.tsx` and `client/src/pages/steps/Results.tsx`. | | The SDK setup | `client/src/utils/sdk-config.ts` and `client/src/context/WizardContext.tsx` (client), `createPrivateSDK` in `server/index.ts` (server). | | When the computation starts and how the output is published | `server/index.ts`. The server schedules the job when the input window closes. It skips an E3 with fewer than two inputs. | -| The program server and its proof | `.interfold/support/dev/src/main.rs`. `interfold init` copies it from `crates/support-scripts/dev`. | +| The program server and its proof | `.interfold/support/dev/src/main.rs` (unproved) and `.interfold/support/openvm` (OpenVM). `interfold init` copies both from `crates/support-scripts`. | +| What the guest proves with | `guest/openvm.toml` (the VM extensions) and the `openvm-hashes` feature of `program/Cargo.toml`. A change gives a new receipt identity. | | The local ciphernodes | The `nodes` section of `interfold.config.yaml` and `scripts/dev_ciphernodes.sh`. Both files must list the same nodes. | | The local chain | The `anvil` command in `scripts/dev_all_concurrently.sh` and `scripts/anvil-automine.mjs`. | diff --git a/docs/pages/build/quick-start.mdx b/docs/pages/build/quick-start.mdx index e832bb63d8..29bb7e71cb 100644 --- a/docs/pages/build/quick-start.mdx +++ b/docs/pages/build/quick-start.mdx @@ -40,9 +40,8 @@ interfold init my-first-e3 ``` `interfold init` downloads the template that matches your CLI version (tag `v0.18.0` for CLI -0.18.0). It copies the template to `my-first-e3`, adds the `lib/risc0-ethereum` Git submodule, runs -`pnpm install`, and makes the first Git commit. The command prints -`You can now start building on Interfold` when it completes. +0.18.0). It copies the template to `my-first-e3`, runs `pnpm install`, and makes the first Git +commit. The command prints `You can now start building on Interfold` when it completes. ### Go to the project folder @@ -159,20 +158,20 @@ the chain with `pnpm dev:evm` (a Hardhat node) instead of Anvil. pnpm runs the `predev:all` script before `dev:all`: ```bash -[ ! -f './.interfold/generated/contracts/ImageID.sol' ] && interfold program compile || true +./scripts/compile_program.sh ``` -The template includes `.interfold/generated/contracts/ImageID.sol`, so this script usually does -nothing. When the file is missing, it runs `interfold program compile`. The result of that command -depends on the `program.dev` setting in `interfold.config.yaml`: +The script loads `scripts/lib/dev_config.sh` and runs `interfold program compile`. The local +settings set `E3_PROGRAM__DEV=true` and `TEMPLATE_UNPROVED_TEST=1` unless `TEMPLATE_REAL_PROOFS=1`, +which selects what the command builds: -| `program.dev` | `interfold program compile` runs | -| --------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| `true` (the template) | `.interfold/support/dev/compile`, which runs `cargo build --locked --bin e3-support-scripts-dev`. No zkVM image is built. | -| `false` | `.interfold/support/ctl/compile` in the `e3-support` Docker container. The RISC Zero build writes `ImageID.sol`. | +| Mode | `interfold program compile` runs | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| Dev mode (the local default) | `.interfold/support/dev/compile`, which runs `cargo build --locked --bin e3-support-scripts-dev`. No guest is built. | +| `TEMPLATE_REAL_PROOFS=1` | `.interfold/support/openvm/compile`: the OpenVM guest in `guest/`, its keys and receipt identity, and the proving service. | -In dev mode, the program server runs the computation without a proof. The template also deploys -`MockRISC0Verifier`, which accepts any RISC Zero seal. See +In dev mode, the program server runs the computation without a proof, and the template deploys +`MockOpenVmReceiptVerifier`, which accepts every receipt on the local chain only. See [Compute provider](/build/e3-program/compute-provider) for proofs. ## What just happened diff --git a/docs/pages/build/sdk.mdx b/docs/pages/build/sdk.mdx index 0b288b7e64..6e79778af1 100644 --- a/docs/pages/build/sdk.mdx +++ b/docs/pages/build/sdk.mdx @@ -461,7 +461,7 @@ The main entry point exports these utilities. | `encodeCustomParams(params)` | The JSON of an object as hex bytes. | | `encodeBfvParams(params)` | ABI-encoded BFV parameters. It throws `MISSING_ERROR1_VARIANCE` without `error1Variance`. | | `decodePlaintextOutput(hex)` | The first 8 bytes as a little-endian unsigned integer, as a `number`. `null` when the input is too short. | -| `DEFAULT_COMPUTE_PROVIDER_PARAMS` | `{ name: 'risc0', parallel: false, batch_size: 2 }` | +| `DEFAULT_COMPUTE_PROVIDER_PARAMS` | `{ name: 'openvm', parallel: false, batch_size: 2 }` | | `DEFAULT_E3_CONFIG` | `{ committeeSize: 0, duration: 1800, payment_amount: '0' }` | | `isValidAddress(value)`, `isValidHash(value)` | Format checks for a 20-byte address and a 32-byte hash. | | `sleep(ms)`, `formatBigInt`, `parseBigInt`, `formatEventName`, `parseEventData`, `generateEventId` | Small helpers. | diff --git a/docs/pages/build/tutorials/deploy-to-testnet.mdx b/docs/pages/build/tutorials/deploy-to-testnet.mdx index 7557d2690e..1098baf7d6 100644 --- a/docs/pages/build/tutorials/deploy-to-testnet.mdx +++ b/docs/pages/build/tutorials/deploy-to-testnet.mdx @@ -21,8 +21,9 @@ register it, and your server and client use the testnet. Do not submit real private data on Sepolia. The `insecure-512` preset is not secure. The public key, decryption, and DKG verifiers of the Sepolia deployment check the proofs. The ciphertext - verifier wraps `MockRISC0Verifier`, which accepts every seal. The other test contracts are - `MockUSDC` and the `Faucet`. The manifest marks Sepolia with `mocks: false`. + verifier is still the RISC Zero verifier from before OpenVM, and it wraps `MockRISC0Verifier`, + which accepts every seal. The other test contracts are `MockUSDC` and the `Faucet`. The manifest + marks Sepolia with `mocks: false`. @@ -65,12 +66,12 @@ as the ticket collateral. Locally, `pnpm dev:all` deploys its own Interfold contracts, and the deployer owns them. On Sepolia, the Interfold team owns the protocol contracts. This changes four steps of the local flow. -| Step | Local (`pnpm dev:all`) | Sepolia | -| ---------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | -| Program registration | `deployTemplate` calls `registerE3Program`. | `registerE3Program` is `onlyOwner`. The owner of the Interfold contract must call it. | -| Protocol ciphertext verifier | `deployTemplate` calls `setCiphertextVerifier` with your image ID. | `setCiphertextVerifier` is `onlyOwner`. One verifier accepts dev-mode proofs for every BFV program. | -| Data availability | The coordination server stores the output (`mode: mock_http`). | Ciphernodes read the output from Avail (`mode: avail`). | -| Ciphernodes | Five local nodes from `scripts/dev_ciphernodes.sh`. | The nodes of registered operators. Sortition needs enough of them for the committee size. | +| Step | Local (`pnpm dev:all`) | Sepolia | +| ---------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| Program registration | `deployTemplate` calls `registerE3Program`. | `registerE3Program` is `onlyOwner`. The owner of the Interfold contract must call it. | +| Protocol ciphertext verifier | `deployTemplate` calls `setCiphertextVerifier` with your receipt identity. | `setCiphertextVerifier` is `onlyOwner`. One mock-backed verifier accepts every BFV program's proofs. | +| Data availability | The coordination server stores the output (`mode: mock_http`). | Ciphernodes read the output from Avail (`mode: avail`). | +| Ciphernodes | Five local nodes from `scripts/dev_ciphernodes.sh`. | The nodes of registered operators. Sortition needs enough of them for the committee size. | The first two rows mean that you cannot run `deployTemplate` on Sepolia unchanged. The owner-only calls revert for any other signer. The last two rows decide if an E3 of your program can complete. @@ -168,10 +169,14 @@ chains: ### Write a Sepolia deploy script Create `scripts/deploy-sepolia.ts`. It is `deploy/default.ts` without the two owner-only calls. Like -the CRISP deploy script, it deploys `PoseidonT3` when the network has no record for it. +the CRISP deploy script, it deploys `PoseidonT3` when the network has no record for it. It deploys +an `OpenVmReceiptVerifier` for the guest that `interfold program compile` built (see +[Compute Provider](/build/e3-program/compute-provider#run-a-compute-provider)), so run that first. ```ts filename="scripts/deploy-sepolia.ts" import { + compiledOpenVmEnvironment, + deployOpenVmReceiptVerifier, getDeploymentChain, readDeploymentArgs, storeDeploymentArgs, @@ -181,7 +186,9 @@ import hre from 'hardhat' async function main() { const { MyProgram__factory: MyProgramFactory } = await import('../types/factories/contracts') - const { ensureTemplateCwd, INTERFOLD_CONFIG_FILE } = await import('./template-paths') + const { ensureTemplateCwd, INTERFOLD_CONFIG_FILE, TEMPLATE_ROOT } = await import( + './template-paths' + ) ensureTemplateCwd() const { ethers } = await hre.network.connect() const [owner] = await ethers.getSigners() @@ -203,15 +210,13 @@ async function main() { ) } - // MockRISC0Verifier accepts every seal, so it weakens only the check in MyProgram.verify. It does - // not change the protocol check. On Sepolia, Risc0BfvCiphertextVerifier wraps a mock verifier too, - // so it accepts dev-mode proofs. The mainnet verifier does not. Use a real RISC Zero verifier for - // real proofs. - const verifier = await ethers.deployContract('MockRISC0Verifier') - await verifier.waitForDeployment() - const imageId = await ethers.deployContract('ImageID') - await imageId.waitForDeployment() - const programId = await imageId.PROGRAM_ID() + // The receipt verifier for the guest in .interfold/caches/openvm/prover.json, unless OPENVM_* + // settings name another. It deploys the Halo2 verifier from the checked artifact first. + const { receipt: verifier } = await deployOpenVmReceiptVerifier( + ethers, + compiledOpenVmEnvironment(TEMPLATE_ROOT), + ) + const programId = await verifier.imageId() const factory = await ethers.getContractFactory( MyProgramFactory.abi, @@ -276,9 +281,9 @@ with `E3ProgramNotAllowed`. ### Check the protocol ciphertext verifier Every output proof must pass the ciphertext verifier that the owner set for BFV. On Sepolia, this is -`Risc0BfvCiphertextVerifier` at `0x52569C1D143bA4B423f19904b58A1271756fc991`. It wraps -`MockRISC0Verifier` at `0x254Cef2769D589E36208e9bD2da031A568fa49cD`. The mock verifier accepts every -seal. Read the verifier address: +still `Risc0BfvCiphertextVerifier` at `0x52569C1D143bA4B423f19904b58A1271756fc991`, from before +OpenVM. It wraps `MockRISC0Verifier` at `0x254Cef2769D589E36208e9bD2da031A568fa49cD`, which accepts +every seal. Read the verifier address: ```bash cast call $INTERFOLD_ADDRESS "getCiphertextVerifier(bytes32)(address)" $(cast keccak "fhe.rs:BFV") --rpc-url $RPC_URL @@ -291,15 +296,16 @@ cast call "imageId()(bytes32)" --rpc-url $RPC_URL cast call "risc0Verifier()(address)" --rpc-url $RPC_URL ``` -The verifier records an image ID, but the mock verifier does not check the seal against it. A proof -from any guest passes the protocol check on Sepolia. The program server in dev mode -(`program.dev: true`) makes dev-mode proofs, and the protocol verifier accepts them. Your program -must still pass `MyProgram.verify`. +The verifier records an image ID, but the mock verifier does not check the seal against it. Its +envelope has the same `abi.encode(bytes seal, bytes32 paramsHash, bytes32 inputRoot)` layout as an +OpenVM proof, so an OpenVM proof passes the protocol check on Sepolia when its parameter hash +matches, and so does a development-runner proof. Your program must still pass `MyProgram.verify`, +which checks the OpenVM receipt for real. -Do not rely on this behavior on mainnet. The mainnet ciphertext verifier checks the seal against a -pinned guest image ID. +Do not rely on this behavior on mainnet. A non-mock ciphertext verifier checks every proof against +its pinned identity, and an OpenVM migration replaces it with `OpenVmBfvCiphertextVerifier`. -A mock RISC Zero verifier in your program affects only `MyProgram.verify`. It does not affect the +The receipt verifier in your program affects only `MyProgram.verify`. It does not affect the protocol verifier. The Interfold contract copies the current verifier into each E3 at request time, so a later change applies only to new requests. See [Verify the Compute Provider](/build/e3-program/verify-compute-provider). @@ -442,7 +448,7 @@ chains it refuses mocks unless `ALLOW_MOCKS_ON_PRODUCTION=true` is set. | `FeeExceedsMaximum` on request | The fee changed after the quote. | Get a new quote and request again. | | `InvalidInputDeadlineStart` on request | `inputWindow[0]` is earlier than the block time. | Compute the window with `calculateInputWindow(publicClient, duration)`. | | No committee key | Sortition did not select a full committee, or the DKG did not finish. | Read the stage with `getE3Stage`. If it is `Failed`, request a new E3. | -| `InvalidOutput` on output publication | The protocol verifier or `MyProgram.verify` rejected the compute proof. | On Sepolia, dev-mode proofs pass the protocol verifier. Check `MyProgram.verify`. | +| `InvalidOutput` on output publication | The protocol verifier or `MyProgram.verify` rejected the compute proof. | Check that the service's guest has the identity your `MyProgram` names. | | `RequestsPaused` on request | Sepolia requests are paused. | Wait until the owner unpauses requests. `requestsPaused()` returns `false` then. | | The E3 does not finish after the output | The committee cannot read the output from Avail. | Replace the local data-availability check, and publish the output to Avail. | @@ -458,7 +464,7 @@ chains it refuses mocks unless `ALLOW_MOCKS_ON_PRODUCTION=true` is set. icon='chip' tag='Build' > - Run the program server with real RISC Zero proofs. + Run the program server with real OpenVM proofs. Request parameters, quotes, and fees in detail. diff --git a/docs/pages/build/tutorials/write-e3-program.mdx b/docs/pages/build/tutorials/write-e3-program.mdx index ff7c50ea02..ed05fe8198 100644 --- a/docs/pages/build/tutorials/write-e3-program.mdx +++ b/docs/pages/build/tutorials/write-e3-program.mdx @@ -121,10 +121,10 @@ pub fn policy() -> InputPolicy { InputPolicy::default() } -pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { +pub fn fhe_processor(fhe_inputs: FHEProcessorInput<'_>) -> Vec { let mut sum = Ciphertext::zero(fhe_inputs.params); - for ciphertext_bytes in fhe_inputs.ciphertexts { - let ciphertext = Ciphertext::from_bytes(&ciphertext_bytes.0, fhe_inputs.params).unwrap(); + for (bytes, _) in fhe_inputs.ciphertexts { + let ciphertext = Ciphertext::from_bytes(&bytes, fhe_inputs.params).unwrap(); sum += &ciphertext; } @@ -133,7 +133,8 @@ pub fn fhe_processor(fhe_inputs: &FHEProcessorInput<'_>) -> Vec { ``` - `fhe_processor` adds the ciphertexts homomorphically and returns the encrypted sum. It never sees - a plaintext. + a plaintext. The ciphertexts arrive one at a time, which is how the OpenVM guest proves rounds + larger than its memory. - `policy` returns `InputPolicy::default()`. The input tree leaf is the SAFE commitment of each ciphertext, and the processor uses every input. This matches `MyProgram.publishInput`, which inserts the commitment. @@ -158,13 +159,13 @@ When you change the computation, keep these rules: `contracts/MyProgram.sol` implements `IE3Program` and `IE3ProgramDataAvailability`: -| Function | Called by | What the template does | -| ------------------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `supportsInterface` | Interfold contract, at registration | Reports `IE3Program`, `IE3ProgramDataAvailability`, and `IERC165`. Registration fails without them. | -| `validate` | Interfold contract, at request | Stores `keccak256(e3ProgramParams)`, starts an input tree of depth 20, returns `keccak256("fhe.rs:BFV")`. | -| `publishInput` | The data provider, directly | Decodes `(bytes ciphertext, bytes32 commitment)`, inserts the commitment, emits `InputPublished`. | -| `verify` | Interfold contract, at output publication | Checks the parameter hash and the input root in the proof, rebuilds the journal, calls the RISC Zero verifier. | -| `verifyDataAvailability` | Interfold contract, at output publication | Local only. It accepts the output bytes as their own receipt. | +| Function | Called by | What the template does | +| ------------------------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| `supportsInterface` | Interfold contract, at registration | Reports `IE3Program`, `IE3ProgramDataAvailability`, and `IERC165`. Registration fails without them. | +| `validate` | Interfold contract, at request | Stores `keccak256(e3ProgramParams)`, starts an input tree of depth 20, returns `keccak256("fhe.rs:BFV")`. | +| `publishInput` | The data provider, directly | Decodes `(bytes ciphertext, bytes32 commitment)`, inserts the commitment, emits `InputPublished`. | +| `verify` | Interfold contract, at output publication | Checks the parameter hash and the input root in the proof, rebuilds the journal, calls the receipt verifier. | +| `verifyDataAvailability` | Interfold contract, at output publication | Local only. It accepts the output bytes as their own receipt. | The template `publishInput` checks only the end of the input window. Add the stage check and the start-of-window check that `CRISPProgram` makes. Add two errors next to the other errors: @@ -218,11 +219,13 @@ comparison is the only check that the output covers your inputs. `deployInterfold(true, false)`, which deploys the protocol with mocks. `deployTemplate` does these steps: -1. It deploys `MockRISC0Verifier`, which accepts every proof, and the `ImageID` library. -2. It deploys `Risc0BfvCiphertextVerifier` for the image ID and calls `setCiphertextVerifier` on the - Interfold contract. -3. It deploys `MyProgram` with the Interfold address, the verifier, and the image ID. It links - `PoseidonT3` for the input tree. +1. With `TEMPLATE_UNPROVED_TEST=1` (the local default), it deploys `MockOpenVmReceiptVerifier`, + which accepts every proof on the local chain only. Otherwise it deploys an + `OpenVmReceiptVerifier` for the guest that `interfold program compile` built. +2. It deploys `OpenVmBfvCiphertextVerifier` for that receipt identity and calls + `setCiphertextVerifier` on the Interfold contract. +3. It deploys `MyProgram` with the Interfold address, the receipt verifier, and its identity. It + links `PoseidonT3` for the input tree. 4. It calls `registerE3Program` and checks `e3Programs(program)`. 5. It records the addresses in `deployed_contracts.json` and `interfold.config.yaml`. @@ -336,13 +339,13 @@ committee key is published or before `inputWindow[0]`. A change in one part often needs a change in another part. Check this table after each change. -| Value | Where it is set | Where it must match | -| ----------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------- | -| Input encoding | `abi.decode(data, (bytes, bytes32))` in `publishInput` | `encodeAbiParameters` in `client/src/utils/input.ts` and `server/input.ts` | -| Input tree leaf | `inputs[e3Id]._insert(uint256(ciphertextCommitment))` | `policy()` in `program/src/lib.rs` | -| Input event | `InputPublished(e3Id, data, index)` | `getContractEvents` in `server/index.ts` | -| BFV parameter set | `paramSet: 0` in the request | `thresholdBfvParamsPresetName: 'INSECURE_THRESHOLD_512'` in the SDK config | -| Guest image ID | `.interfold/generated/contracts/ImageID.sol` | The `imageId` in the `MyProgram` constructor and in `Risc0BfvCiphertextVerifier` | +| Value | Where it is set | Where it must match | +| ----------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| Input encoding | `abi.decode(data, (bytes, bytes32))` in `publishInput` | `encodeAbiParameters` in `client/src/utils/input.ts` and `server/input.ts` | +| Input tree leaf | `inputs[e3Id]._insert(uint256(ciphertextCommitment))` | `policy()` in `program/src/lib.rs` | +| Input event | `InputPublished(e3Id, data, index)` | `getContractEvents` in `server/index.ts` | +| BFV parameter set | `paramSet: 0` in the request | `thresholdBfvParamsPresetName: 'INSECURE_THRESHOLD_512'` in the SDK config | +| Receipt identity | `guest/` and `program/`, built by `interfold program compile` | The `imageId` in the `MyProgram` constructor and in `OpenVmBfvCiphertextVerifier` | ## The E3 flow diff --git a/docs/pages/learn/architecture.mdx b/docs/pages/learn/architecture.mdx index a20735f798..a291451b18 100644 --- a/docs/pages/learn/architecture.mdx +++ b/docs/pages/learn/architecture.mdx @@ -29,7 +29,7 @@ network. Each application brings its own program contract, servers, and client. { name: 'Compute', note: 'Off-chain', - items: ['Compute provider (RISC Zero zkVM)', 'Data-availability layer'], + items: ['Compute provider (OpenVM zkVM)', 'Data-availability layer'], }, { name: 'Ciphernode network', @@ -83,7 +83,7 @@ time. Governance can replace these contracts only after it pauses requests and a | `BfvPkVerifier` | The recursive DKG proof. It calls the generated Honk verifier `DkgAggregatorVerifier`. | `publishCommittee` | | `DkgFoldAttestationVerifier` | One signed fold attestation from each accepted DKG party | `publishCommittee` | | `BfvDecryptionVerifier` | The recursive decryption proof. It calls the Honk verifier `DecryptionAggregatorVerifier`. | `publishPlaintextOutput` | -| `Risc0BfvCiphertextVerifier` | The protocol fields in the RISC Zero compute receipt | `publishCiphertextOutput` | +| `OpenVmBfvCiphertextVerifier` | The protocol fields in the OpenVM compute receipt | `publishCiphertextOutput` | | `AvailVectorXDataAvailabilityVerifier` | Avail blob inclusion through the VectorX bridge, for E3 programs that use Avail | The E3 program | `BfvPkVerifierRouter` and `BfvDecryptionVerifierRouter` can sit in front of the BFV verifiers. A @@ -126,8 +126,9 @@ role. ### Compute provider The compute provider runs the secure process over the ciphertexts. In the current code, it is the -RISC Zero zkVM. The zkVM receipt binds the E3, the committee public key, the input Merkle root, and -the output hash. See [Compute Provider](/build/e3-program/compute-provider). +OpenVM zkVM, run on the operator's GPU or CPU. The receipt binds the E3, the committee public key, +the input Merkle root, and the output hash. Deployed networks keep their RISC Zero verifiers until +an OpenVM migration. See [Compute Provider](/build/e3-program/compute-provider). ### Program server diff --git a/docs/pages/learn/cryptography.mdx b/docs/pages/learn/cryptography.mdx index 7fa3666a8b..b23b51c321 100644 --- a/docs/pages/learn/cryptography.mdx +++ b/docs/pages/learn/cryptography.mdx @@ -164,7 +164,7 @@ form four phases: | P4: Threshold decryption | Members make decryption shares, and the aggregator combines T + 1 | C6, C7 | The FHE computation runs between P3 and P4. The compute provider proves it with its own proof system -(the RISC Zero zkVM in the current code), not with these circuits. +(the OpenVM zkVM in the current code), not with these circuits. A failed proof is attributable to one member. Other members then start an accusation, which can lead to a slash. See [Commitment consistency](/internals/commitment-consistency) and diff --git a/docs/pages/learn/index.mdx b/docs/pages/learn/index.mdx index 7f41836e69..3d8e6e0c51 100644 --- a/docs/pages/learn/index.mdx +++ b/docs/pages/learn/index.mdx @@ -57,7 +57,7 @@ The table shows each guarantee, the mechanism that backs it, and where the proto | Inputs stay encrypted during the computation | Fully homomorphic encryption (FHE) with the threshold BFV scheme | The compute provider receives only ciphertexts | | No single party can decrypt | Threshold cryptography: DKG and Shamir secret sharing | The decryption proof combines T + 1 verified shares | | Key generation and decryption are correct | Zero-knowledge (ZK) proofs from circuits C0 to C7 | `BfvPkVerifier` at `publishCommittee`, `BfvDecryptionVerifier` at `publishPlaintextOutput` | -| The computation is correct | A compute proof (a RISC Zero zkVM receipt in the current code) | The ciphertext verifier and the E3 program `verify` function at `publishCiphertextOutput` | +| The computation is correct | A compute proof (an OpenVM zkVM receipt in the current code) | The ciphertext verifier and the E3 program `verify` function at `publishCiphertextOutput` | | Committee selection is random | Ticket-weighted sortition with a Chainlink VRF v2.5 seed | `CiphernodeRegistry` functions `submitTicket` and `finalizeCommittee` | | Operators have a reason to act correctly | Economic security: FOLD bonds, tFOLD tickets, slashing, rewards, refunds | `BondingRegistry`, `SlashingManager`, and `E3RefundManager` | diff --git a/docs/pages/learn/use-cases.mdx b/docs/pages/learn/use-cases.mdx index dfc5ab9a9a..60a13c3182 100644 --- a/docs/pages/learn/use-cases.mdx +++ b/docs/pages/learn/use-cases.mdx @@ -34,7 +34,7 @@ CRISP (Coercion-Resistant Impartial Selection Protocol) is the reference applica | Inputs | Each voter encrypts a ballot in the browser under the committee key. | | Input proof | The client generates a Noir proof that the ballot is valid. `CRISPProgram.sol` verifies it. | | Data availability | The ciphertext bytes go to Avail. The program checks the VectorX receipt. | -| Secure process | A RISC Zero program adds the encrypted ballots into an encrypted tally. | +| Secure process | An OpenVM program adds the encrypted ballots into an encrypted tally. | | Output | The committee decrypts only the tally. Individual ballots stay encrypted. | CRISP has its own contracts, Noir circuits, a Rust coordination server, and a React client. Start diff --git a/docs/pages/learn/what-is-e3.mdx b/docs/pages/learn/what-is-e3.mdx index 957bd082a0..4cfbe0f8e2 100644 --- a/docs/pages/learn/what-is-e3.mdx +++ b/docs/pages/learn/what-is-e3.mdx @@ -92,7 +92,7 @@ The committee runs DKG. The public key comes from H accepted contributions, and ### Compute provider The compute provider runs the secure process over the published inputs after the input window -closes. In the current code, the compute provider is the RISC Zero zkVM. The template and CRISP both +closes. In the current code, the compute provider is the OpenVM zkVM. The template and CRISP both use it. The zkVM produces a receipt that proves which program ran over which inputs. The ciphertext output is stored on a data-availability layer. The Interfold contract stores only the diff --git a/docs/pages/reference/cli.mdx b/docs/pages/reference/cli.mdx index c9ac681de8..0aadfc5be5 100644 --- a/docs/pages/reference/cli.mdx +++ b/docs/pages/reference/cli.mdx @@ -171,9 +171,10 @@ These commands make and run an E3 project from the template. For a walkthrough, ### `interfold init` -Makes a new Interfold project from a template. The command clones the template, copies the support -scripts to `.interfold/support`, adds the `lib/risc0-ethereum` submodule, runs `pnpm install`, and -makes the first Git commit. It needs `git` and `pnpm`. +Makes a new Interfold project from a template. The command clones the template, pins its Interfold +crates to the cloned commit, copies the development runner and the OpenVM proving service to +`.interfold/support`, runs `pnpm install`, and makes the first Git commit. It needs `git` and +`pnpm`. ```bash interfold init [PATH] [--template