diff --git a/.dockerignore b/.dockerignore index 6000c736f3..bf8660cb7b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,13 @@ !Cargo.toml !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 @@ -24,3 +31,9 @@ target/ # Explicitly ignore node_modules **/node_modules/ + +# Never send local secrets to an image: a checkout's .env files can hold deployment keys. These +# rules come last so that no allow rule above can bring a .env file back. +**/.env +**/.env.* +!**/.env.example diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4011f79b9c..f2703f36f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,8 @@ jobs: build_sdk: ${{ steps.jobs.outputs.build_sdk }} sdk_tests: ${{ steps.jobs.outputs.sdk_tests }} build_e3_support_dev: ${{ steps.jobs.outputs.build_e3_support_dev }} + openvm_worker: ${{ steps.jobs.outputs.openvm_worker }} + openvm_guest: ${{ steps.jobs.outputs.openvm_guest }} build_circuits: ${{ steps.jobs.outputs.build_circuits }} noir_checks: ${{ steps.jobs.outputs.noir_checks }} integration_prebuild: ${{ steps.jobs.outputs.integration_prebuild }} @@ -92,6 +94,35 @@ jobs: - 'rust-toolchain.toml' - '!**/*.md' - '!**/*.mdx' + # The OpenVM worker is a cargo workspace of its own, built against the OpenVM SDK. + openvm_worker: + - 'crates/openvm-prover/**' + - '!**/*.md' + - '!**/*.mdx' + # What the OpenVM guests compile: each project's program and guest, and the crates they + # link, some of them under guest-only cfg flags. + openvm_guest: + - 'Cargo.toml' + - 'crates/bfv-client/**' + - 'crates/compute-provider/**' + - 'crates/fhe-params/**' + - 'crates/openvm-types/**' + - 'crates/parity-matrix/**' + - 'crates/polynomial/**' + - 'crates/safe/**' + - 'crates/zk-helpers/**' + # The programs inherit dependencies from their project workspace, and the native + # fixture builds in CRISP's. + - 'examples/CRISP/Cargo.toml' + - 'examples/CRISP/Cargo.lock' + - 'examples/CRISP/guest/**' + - 'examples/CRISP/program/**' + - 'templates/default/Cargo.toml' + - 'templates/default/guest/**' + - 'templates/default/program/**' + - 'scripts/run-openvm.sh' + - '!**/*.md' + - '!**/*.mdx' contracts: - 'packages/interfold-contracts/**' # The manifest is generated from deployed_contracts.json and @@ -117,8 +148,9 @@ jobs: - 'examples/CRISP/Cargo.toml' - 'examples/CRISP/Cargo.lock' - 'examples/CRISP/rust-toolchain.toml' - # A symlink to a member of the CRISP cargo workspace. + # Symlinks to members of the CRISP cargo workspace. - 'examples/CRISP/.interfold/support/dev' + - 'examples/CRISP/.interfold/support/openvm' - 'examples/CRISP/crates/**' - 'examples/CRISP/program/**' - 'examples/CRISP/server/**' @@ -253,6 +285,8 @@ jobs: DOCKER="${{ steps.filter.outputs.docker }}" CI="${{ steps.filter.outputs.ci }}" TOOLING="${{ steps.filter.outputs.tooling }}" + OPENVM_WORKER="${{ steps.filter.outputs.openvm_worker }}" + OPENVM_GUEST="${{ steps.filter.outputs.openvm_guest }}" FORCE="${{ github.event_name == 'workflow_dispatch' || inputs.release_candidate }}" any() { for v in "$@"; do [ "$v" = "true" ] && echo "true" && return; done; echo "false"; } @@ -289,7 +323,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 @@ -298,6 +333,8 @@ jobs: # Both feed template_integration, so each must cover every path that # triggers it — a skipped dependency silently skips the e2e job. echo "build_e3_support_dev=$(any $FORCE $TEMPLATES $RUST $CONTRACTS $CIRCUITS $SDK $CI $TOOLING)" >> $GITHUB_OUTPUT + echo "openvm_worker=$(any $FORCE $OPENVM_WORKER $CI)" >> $GITHUB_OUTPUT + echo "openvm_guest=$(any $FORCE $OPENVM_GUEST $CI)" >> $GITHUB_OUTPUT # build_circuits runs check:verifiers, so every input of the generated verifiers runs it. # CIRCUIT_BUILD adds the other files that the job runs or hashes. echo "build_circuits=$(any $FORCE $RUST $CIRCUITS $VERIFIERS $CIRCUIT_BUILD $CI $TOOLING)" >> $GITHUB_OUTPUT @@ -414,9 +451,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' @@ -590,16 +626,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 +665,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 +1608,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,8 +1619,14 @@ 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 + # The OpenVM proving service links the template program. Its guest needs cargo-openvm and a GPU + # host for proofs, so CI builds only the service. + - name: Build the OpenVM proving service + run: cd templates/default && cargo build --locked --bin e3-support-scripts-openvm - name: Verify build artifacts run: | echo "Checking for support scripts binary:" @@ -1602,6 +1641,78 @@ jobs: retention-days: 1 if-no-files-found: error + # The CPU build of the OpenVM worker and its tests. Proofs and the CUDA build need a GPU host. + openvm_worker: + needs: [detect_changes] + if: needs.detect_changes.outputs.openvm_worker == 'true' + timeout-minutes: 45 + 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', github.run_id, github.run_attempt, + 'openvm_worker') || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Cache Rust dependencies + uses: ./.github/actions/cache-dependencies + with: + cargo-lock-path: crates/openvm-prover/Cargo.lock + rust-target-path: crates/openvm-prover/target/ + - name: Setup Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + - name: Test the CPU worker + run: cargo test --locked --manifest-path crates/openvm-prover/Cargo.toml + + # Builds both OpenVM guests, which compiles the guest-only code paths, then runs CRISP's guest on a + # fresh fixture without proving and compares the digest it reveals with the native journal. + openvm_guest: + needs: [detect_changes] + if: needs.detect_changes.outputs.openvm_guest == 'true' + timeout-minutes: 75 + 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', github.run_id, github.run_attempt, + 'openvm_guest') || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - name: Cache Rust dependencies + uses: ./.github/actions/cache-dependencies + with: + cargo-lock-path: examples/CRISP/**/Cargo.lock + rust-target-path: target/openvm/ + - name: Setup Rust + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + - name: Install protoc + run: sudo apt-get update -y && sudo apt-get install -y protobuf-compiler + - name: Install the OpenVM guest toolchain + run: rustup toolchain install nightly-2026-01-18 --component rust-src + - name: Cache cargo-openvm + id: cargo_openvm + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ~/.cargo/bin/cargo-openvm + key: cargo-openvm-v2.0.2-${{ runner.os }} + - name: Install cargo-openvm + if: steps.cargo_openvm.outputs.cache-hit != 'true' + run: cargo install --locked --git https://github.com/openvm-org/openvm.git --tag v2.0.2 cargo-openvm + - name: Build the template guest + working-directory: templates/default/guest + env: + OPENVM_BUILD_LOCKED: '1' + RUSTFLAGS: --cfg crisp_openvm --cfg crisp_fhe_optimized + run: cargo openvm build --target-dir ../../../target/openvm/template-guest + # The guest replaces hashing, packing and commitments with accelerated versions that the host + # does not run. The secure fixture covers their secure-8192 widths. + - name: Run the CRISP guest against the native journal + run: | + bash scripts/run-openvm.sh fixture 3 "$RUNNER_TEMP/crisp-fixture" --insecure + bash scripts/run-openvm.sh guest-parity "$RUNNER_TEMP/crisp-fixture" + bash scripts/run-openvm.sh fixture 2 "$RUNNER_TEMP/crisp-fixture-secure" + bash scripts/run-openvm.sh guest-parity "$RUNNER_TEMP/crisp-fixture-secure" + build_sdk: needs: [detect_changes] if: needs.detect_changes.outputs.build_sdk == 'true' @@ -1843,8 +1954,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..a069cc5fc4 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: | @@ -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 6b0311c16b..66491818ae 100644 --- a/.gitignore +++ b/.gitignore @@ -19,17 +19,23 @@ __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/ -# 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/.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/.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/Cargo.lock b/Cargo.lock index 6f486e58a4..837c6cce9a 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", @@ -4328,6 +4329,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "e3-openvm-host" +version = "0.19.0-test.2" +dependencies = [ + "anyhow", + "e3-compute-provider", + "e3-openvm-types", + "libc", + "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" @@ -4363,6 +4385,7 @@ dependencies = [ "e3-bfv-client", "e3-compute-provider", "e3-fhe-params", + "futures-util", "hex", "reqwest", "serde", @@ -4400,9 +4423,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", ] @@ -5047,7 +5073,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?tag=v0.4.2#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "bincode", "doc-comment", @@ -5073,7 +5099,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?tag=v0.4.2#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "ethnum", "fhe-traits", @@ -5097,7 +5123,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?tag=v0.4.2#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "rand 0.9.5", ] @@ -5105,7 +5131,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?tag=v0.4.2#873dc69c07eae251f88c4b5cacf6c4453e2c365a" dependencies = [ "num-bigint-dig", "num-traits", @@ -6221,12 +6247,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 +7896,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.5", ] [[package]] @@ -7954,6 +7975,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 +8263,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 +9584,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 +10870,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 +10896,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 +10939,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 +12105,7 @@ dependencies = [ "num-derive", "num-traits", "smallvec", - "spin", + "spin 0.9.9", "wasmi_collections", "wasmi_core", "wasmparser-nostd", diff --git a/Cargo.toml b/Cargo.toml index 329fa69e05..2cad43d1c2 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" } @@ -157,10 +162,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", tag = "v0.4.2", features = ["experimental-mbfv"] } +fhe-traits = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.2" } +fhe-math = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.2" } +fhe-util = { git = "https://github.com/gnosisguild/fhe.rs", tag = "v0.4.2" } figment = { version = "=0.10.19", features = ["env", "yaml", "test"] } futures = "=0.3.31" futures-util = "=0.3.31" 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..7aad2ea220 100644 --- a/agent/CRATES_ARCHITECTURE.md +++ b/agent/CRATES_ARCHITECTURE.md @@ -1397,3 +1397,29 @@ 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 + +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 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; 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..40251c654a 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. | @@ -601,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/04_DKG_AND_COMPUTATION.md b/agent/flow-trace/04_DKG_AND_COMPUTATION.md index 6b52da8269..2a00880011 100644 --- a/agent/flow-trace/04_DKG_AND_COMPUTATION.md +++ b/agent/flow-trace/04_DKG_AND_COMPUTATION.md @@ -1124,32 +1124,37 @@ 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 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 build swaps in accelerated hashing, packing and +commitment code (see `invariants/02`). 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 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 value, and depth rule. -The guest derives the input root from the ciphertexts it processed. `ComputeInput` holds only -`fhe_inputs`, and `ComputeInput::run_batched` calls `MerkleTreeBuilder::compute_leaf_hashes_batched` -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. +The guest derives the input root from the ciphertexts it processed. Its input carries no root or +leaf, and `SecureProcess::absorb` builds each leaf from the ciphertext it reads, before the tree is +built (`crates/compute-provider/src/secure_process.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 @@ -1947,14 +1952,25 @@ after the complete key publication arrives and passes that commitment check. - leaves are **derived** from the ciphertexts the Secure Process consumed, never received alongside them; -- **every** published input contributes a leaf, whatever is computed over. +- **every** published input contributes a leaf, whatever is computed over; +- the selected ciphertexts the processor reads are the ones the leaves were built from. + +`SecureProcess` reads a round in two passes, one ciphertext at a time. The first pass reads every +ciphertext in index order and keeps its leaf, recomputed commitment and Keccak hash. Selection then +runs over those records. The second pass reads the selected ciphertexts again, and refuses one whose +hash differs from its first read (`InputChanged`), a first pass that is short or long +(`InputCount`), and a processor that stops before the last selected input (`Unread`). The guest +therefore holds one ciphertext at a time, and its memory does not bound a round. `ComputeInput::run` +runs the same code over a round held in memory. The host's predicted journal and the guest's agree +while the guest's accelerated hashing, packing and commitments match the reference code the host +runs; unit tests and the CI guest-parity check (an insecure and a secure fixture) cover that. The leaf layout and which inputs are computed over come from the program, as an `InputPolicy`: ```rust pub struct InputPolicy { pub leaf: fn(&PublishedInput) -> Result, - pub select: fn(&[PublishedInput]) -> Vec, + pub select: fn(&[InputRecord]) -> Vec, } ``` @@ -1966,19 +1982,28 @@ answers differently from a program where every input counts. commitment and every input is computed over — and matches the starter template, whose `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. +`select` sees an `InputRecord`: the published input without its ciphertext bytes, which the Secure +Process no longer holds at selection time. The processor receives the selected ciphertexts as an +iterator. + +Each project's guest (`guest/`) and proving service (`.interfold/support/openvm`) link the project's +own `program/`. A policy or processor 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 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 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 compile` builds the project's guest, its keys, the receipt identity and the +worker configuration, and `interfold program start` runs the project's service with the +`program.openvm` workers. The service picks the CUDA worker when it is configured and its probe +opens a GPU, and the CPU worker otherwise, and runs the worker's `check` before it accepts work. +Every worker run has a deadline. 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 @@ -2005,9 +2030,9 @@ leaf = sha256(keccak256(encryptedVote) || encryptedVoteCommitment || slotAddress - the **parent**, because the guest walks each slot's chain by it — an unbound parent would let a prover re-point entries and change which one holds the slot. -`MerkleTreeBuilder::compute_leaf_hashes_batched` rebuilds exactly that layout. Both sides pin the -same test vector (`program/tests/input_leaf.rs` and `tests/input-leaf.test.ts`), and -`examples/CRISP/program/tests/onchain_root_agreement.rs` asserts Rust reproduces a root a real +The CRISP `policy::leaf`, which `SecureProcess` applies to each input, rebuilds exactly that layout. +Both sides pin the same test vector (`program/tests/input_leaf.rs` and `tests/input-leaf.test.ts`), +and `examples/CRISP/program/tests/onchain_root_agreement.rs` asserts Rust reproduces a root a real contract produced, from a fixture generated by `tests/input-tree-e2e.test.ts`. A one-byte divergence would make every root mismatch and nothing else would detect it. 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/agent/flow-trace/08_DATA_AVAILABILITY.md b/agent/flow-trace/08_DATA_AVAILABILITY.md index f992332728..78617680c4 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,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 RISC Zero -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 @@ -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,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 RISC Zero 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 RISC Zero 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 @@ -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/openvm-prover/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..c847274109 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,14 +440,15 @@ 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 - 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 + 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 - changes there as unaudited. — `packages/interfold-contracts/audits/README.md` + 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 leaf from each supplied input through the E3 program's `InputPolicy`. The protocol verifier @@ -458,16 +459,16 @@ 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. - A program that skips the comparison accepts a result computed over any input set. — + `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.** - `MerkleTreeBuilder::compute_leaf_hashes_batched` computes one leaf per supplied input, in the - supplied order whatever the batching schedule, through the program's `InputPolicy::leaf`, - including inputs that the policy does not select for computation. The caller must supply the - complete input set in on-chain order: a received root can disagree with the data it claims to - describe, and a missing leaf changes the root and makes the result unpublishable. — - `crates/compute-provider/src/merkle_tree_builder.rs`; `flow-trace/04` + `SecureProcess` computes one leaf per supplied input, in the supplied order whatever the batching + schedule, through the program's `InputPolicy::leaf`, including inputs that the policy does not + select for computation. The caller must supply the complete input set in on-chain order: a + received root can disagree with the data it claims to describe, and a missing leaf changes the + root and makes the result unpublishable. — `crates/compute-provider/src/secure_process.rs`; + `flow-trace/04` - **A CRISP input is committed before it is finalized, but computation requires both.** `publishInput` verifies the Noir proof and the configured service's EIP-712 storage attestation, then reserves the leaf and index so a later input can name it as its parent. `finalizeInput` must @@ -494,6 +495,16 @@ every section. universal answer. `InputPolicy::default` is the historical behaviour — leaf is the ciphertext's own commitment, every input counts — which matches the starter template. Every E3 program exports `policy()` beside `fhe_processor`. — `flow-trace/04` +- **The Secure Process holds one ciphertext at a time and checks its second pass.** It reads every + ciphertext once for its leaf, selects over records without bytes, then reads the selected + ciphertexts again and refuses one whose Keccak hash differs from the first read. The host and the + guest run the same `SecureProcess`, but the guest build swaps in accelerated code the host does + not run: OpenVM's Poseidon2 (`e3-safe/openvm`), Keccak and SHA-256 (`openvm-hashes`), and the + power-basis commitment and RNS packing (`crisp_fhe_optimized`). The host's predicted journal is + the guest's only while each accelerated path matches its reference. Unit tests compare them, and + CI runs the real guest against the host's journal on an insecure and a secure fixture + (`pnpm openvm guest-parity`). A mismatch cannot make a false proof, because contracts rebuild the + journal from chain state, but no proof can then be made and every round fails. — `flow-trace/04` - **CRISP binds bytes, commitment, slot and parent into its leaf, and selects the end of each slot's chain.** `CRISPProgram.inputLeaf` is `sha256(keccak256(bytes) || commitment || slot || parentIndexPlusOne) mod SNARK_SCALAR_FIELD` and diff --git a/agent/invariants/04_BUILD_CONFIG.md b/agent/invariants/04_BUILD_CONFIG.md index 5a1cd8c46e..673c4d7a72 100644 --- a/agent/invariants/04_BUILD_CONFIG.md +++ b/agent/invariants/04_BUILD_CONFIG.md @@ -12,9 +12,13 @@ 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. +- **`crates/support/contracts/ImageID.sol` is frozen.** It records the RISC Zero image ID that the + existing CRISP deployments verify. The guest build that generated it is gone, so it cannot be + regenerated, and the secure CRISP upgrade scripts (`scripts/upgrade/secureCrisp.ts` and + `validateSecureCrisp.ts`) still read it to check those deployments. Never edit it; delete it + together with those scripts. - **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 +55,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 +79,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/Dockerfile b/crates/Dockerfile index 0ccde02391..ba007c142e 100644 --- a/crates/Dockerfile +++ b/crates/Dockerfile @@ -70,6 +70,8 @@ COPY crates/layout-lock/Cargo.toml ./layout-lock/Cargo.toml COPY crates/logger/Cargo.toml ./logger/Cargo.toml COPY crates/multithread/Cargo.toml ./multithread/Cargo.toml COPY crates/net/Cargo.toml ./net/Cargo.toml +COPY crates/openvm-host/Cargo.toml ./openvm-host/Cargo.toml +COPY crates/openvm-types/Cargo.toml ./openvm-types/Cargo.toml COPY crates/parity-matrix/Cargo.toml ./parity-matrix/Cargo.toml COPY crates/zk-prover/Cargo.toml ./zk-prover/Cargo.toml COPY crates/polynomial/Cargo.toml ./polynomial/Cargo.toml 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..758c6449fc 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 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 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 2d9975a679..445cb90549 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::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 sha3::{Digest, Keccak256}; 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,15 @@ 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. + /// + /// The on-chain index is what the caller supplied. No leaf, root or journal word binds it, so the + /// output must not depend on it; the ciphertext's position in the round is what the root binds. + pub ciphertexts: &'a mut dyn Iterator, u64)>, pub params: &'a Arc, } @@ -85,6 +89,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,72 +139,61 @@ impl ComputeInput { policy: InputPolicy, batching: Batching, ) -> Result<(ComputeResult, Vec), ComputeError> { - let params = decode_bfv_params_arc(&self.fhe_inputs.params) - .map_err(|e| ComputeError::DecodeParams(e.to_string()))?; - - 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() - ))); - } + self.run_selected(fhe_processor, policy, batching) + .map(|(result, ciphertext, _)| (result, ciphertext)) + } - 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, + /// 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, + ) -> 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, )?; - 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()))?; + 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. - let processed_ciphertext = (fhe_processor)(&FHEProcessorInput { - ciphertexts: &selected, - params: ¶ms, - }); - let processed_hash = Keccak256::digest(&processed_ciphertext).to_vec(); - 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(); - - 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; - fn sum_processor(inputs: &FHEProcessorInput<'_>) -> Vec { + use sha3::{Digest, Keccak256}; + + 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() } @@ -219,12 +221,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 @@ -233,17 +266,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 @@ -264,22 +290,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 @@ -287,29 +304,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" ); } @@ -317,23 +331,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(_)), @@ -363,11 +372,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, .. }), @@ -386,10 +392,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(); @@ -421,13 +424,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 }, ) @@ -449,6 +449,7 @@ mod tests { let agreeing = PublishedInput { index: 0, ciphertext: &bytes, + ciphertext_hash: [0; 32], commitment: Some(&commitment), metadata: &[], recomputed: Some(commitment), @@ -481,11 +482,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, @@ -501,7 +501,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() } @@ -511,12 +511,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, @@ -526,8 +521,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/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..b248f24e69 100644 --- a/crates/compute-provider/src/lib.rs +++ b/crates/compute-provider/src/lib.rs @@ -7,11 +7,14 @@ mod ciphertext_output; mod compute_input; 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..52904cc4f5 --- /dev/null +++ b/crates/compute-provider/src/secure_process.rs @@ -0,0 +1,584 @@ +// 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`]) to predict the journal the guest proves. The guest build +//! swaps in accelerated hashing and packing, so the two agree only while those match the reference +//! code the host runs; unit tests and the CI guest-parity check compare them. + +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 dd87d62a6f..dc27395453 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,9 @@ node: quic_port: 1234 program: - risc0: - risc0_dev_mode: 0 + openvm: + prover_bin: "/deployment/bin/interfold-openvm-prover" + setup_dir: "/deployment/openvm" nodes: ag: @@ -679,10 +680,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 { + prover_bin: Some(PathBuf::from("/deployment/bin/interfold-openvm-prover")), + setup_dir: Some(PathBuf::from("/deployment/openvm")), + ..OpenVmConfig::default() }) ); assert!(config.peers().is_empty()); diff --git a/crates/config/src/program_config.rs b/crates/config/src/program_config.rs index 7d98502eb7..eb74105a6d 100644 --- a/crates/config/src/program_config.rs +++ b/crates/config/src/program_config.rs @@ -4,117 +4,148 @@ // 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. use serde::{Deserialize, Serialize}; +use std::path::PathBuf; -#[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, +/// 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, } -fn default_true() -> bool { - true +impl OpenVmBackend { + pub fn as_str(&self) -> &'static str { + match self { + Self::Auto => "auto", + Self::Cpu => "cpu", + Self::Cuda => "cuda", + } + } } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct Risc0Config { - #[serde(default = "default_risc0_dev_mode")] - pub risc0_dev_mode: u8, +/// 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 { + /// The CPU build of `interfold-openvm-prover`. #[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, - } - } + pub prover_bin: Option, + /// The CUDA build of `interfold-openvm-prover`. + #[serde(default)] + pub prover_bin_cuda: Option, + #[serde(default)] + pub backend: OpenVmBackend, + /// 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)] +#[serde(deny_unknown_fields)] pub struct ProgramConfig { - risc0: Option, + 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 { - 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 { 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)] mod tests { - use super::ProgramConfig; + use super::{OpenVmBackend, ProgramConfig}; + use std::path::PathBuf; #[test] - fn deserializes_dedicated_ipfs_gateway() { + fn deserializes_openvm_worker_configuration() { + let config: ProgramConfig = serde_yaml::from_str( + r#" +openvm: + prover_bin: "/deployment/bin/interfold-openvm-prover" + prover_bin_cuda: "/deployment/bin/interfold-openvm-prover-cuda" + backend: cuda +"#, + ) + .expect("program config must deserialize"); + + let openvm = config.openvm().expect("OpenVM config must be present"); + assert_eq!( + openvm.prover_bin, + Some(PathBuf::from("/deployment/bin/interfold-openvm-prover")) + ); + assert_eq!(openvm.backend, OpenVmBackend::Cuda); + 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()); + } + + /// 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" - private_key: "demo" - pinata_jwt: "demo" - ipfs_gateway_url: "https://dedicated.example" "#, ) - .expect("program config must deserialize"); + .expect("a config with the removed section must still load"); + assert!(config.ensure_supported().is_err()); + assert!(ProgramConfig::default().ensure_supported().is_ok()); + } - let boundless = config - .risc0() - .and_then(|risc0| risc0.boundless.as_ref()) - .expect("Boundless config must be present"); - assert_eq!( - boundless.ipfs_gateway_url.as_deref(), - Some("https://dedicated.example") - ); + #[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..2ba33c903e 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; @@ -151,6 +144,7 @@ async fn install_interfold( r"(?m)^e3-compute-provider =.*\n?", &format!("e3-compute-provider = {{ git = \"https://github.com/theinterfold/interfold\", rev = \"{}\" }}\n",commit_hash), ), + interfold_path_filter(&commit_hash), ], ) .await @@ -170,17 +164,21 @@ async fn install_interfold( .await?; spinner - .run("Setting up support folders ctl and dev", || async { + .run("Setting up the development runner", || async { copy::copy_with_filters( - &PathBuf::from(TEMP_DIR).join("crates/support-scripts/ctl"), - &cwd.join(".interfold/support/ctl"), + &PathBuf::from(TEMP_DIR).join("crates/support-scripts/dev"), + &cwd.join(".interfold/support/dev"), &[], ) - .await?; + .await + }) + .await?; + spinner + .run("Setting up the OpenVM proving service", || async { copy::copy_with_filters( - &PathBuf::from(TEMP_DIR).join("crates/support-scripts/dev"), - &cwd.join(".interfold/support/dev"), + &PathBuf::from(TEMP_DIR).join("crates/support-scripts/openvm"), + &cwd.join(".interfold/support/openvm"), &[], ) .await @@ -217,58 +215,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"); @@ -316,6 +269,21 @@ async fn install_interfold( } // Updated execute function to include workspace dependency substitution +/// The Interfold crates that the template's manifests depend on by path. +const INTERFOLD_TEMPLATE_CRATES: &str = + "program-server|bfv-client|fhe-params|compute-provider|openvm-host|openvm-types|safe"; + +/// Pins an inline path dependency on an Interfold crate, such as the OpenVM guest's, to the +/// template's commit. Only the source changes, so features in the same table are kept. Other path +/// dependencies, and dependencies written as a table of their own, are left as they are. +fn interfold_path_filter(commit_hash: &str) -> Filter { + Filter::new( + "**/Cargo.toml", + &format!(r#"\{{ path = "(?:\.\./)+crates/(?:{INTERFOLD_TEMPLATE_CRATES})""#), + &format!(r#"{{ git = "https://github.com/theinterfold/interfold", rev = "{commit_hash}""#), + ) +} + pub async fn execute( location: Option, template: Option, @@ -393,3 +361,37 @@ pub async fn execute( } } } + +#[cfg(test)] +mod path_filter_tests { + use super::interfold_path_filter; + use regex::Regex; + + #[test] + fn pins_interfold_crates_and_keeps_their_features() { + let filter = interfold_path_filter("abc123"); + let manifest = r#"e3-safe = { path = "../../../crates/safe", features = ["openvm"] } +e3-openvm-types = { path = "../../../crates/openvm-types" } +local-helper = { path = "../crates/local-helper" } +[dependencies.e3-openvm-host] +path = "../../crates/openvm-host" +"#; + let rewritten = Regex::new(&filter.search_pattern) + .unwrap() + .replace_all(manifest, filter.replacement.as_str()) + .to_string(); + + assert!(rewritten.contains( + r#"e3-safe = { git = "https://github.com/theinterfold/interfold", rev = "abc123", features = ["openvm"] }"# + )); + assert!(rewritten.contains( + r#"e3-openvm-types = { git = "https://github.com/theinterfold/interfold", rev = "abc123" }"# + )); + assert!(rewritten.contains(r#"local-helper = { path = "../crates/local-helper" }"#)); + assert!( + rewritten + .contains("[dependencies.e3-openvm-host]\npath = \"../../crates/openvm-host\""), + "a dependency written as its own table is left alone" + ); + } +} 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/openvm-host/Cargo.toml b/crates/openvm-host/Cargo.toml new file mode 100644 index 0000000000..f2e964bef1 --- /dev/null +++ b/crates/openvm-host/Cargo.toml @@ -0,0 +1,16 @@ +[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 } +# A range, not the workspace pin: the CRISP and template workspaces lock a newer 0.2 release. +libc = "0.2" +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..e9bfabb07f --- /dev/null +++ b/crates/openvm-host/src/lib.rs @@ -0,0 +1,575 @@ +// 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: `abi.encode(uint8 version, bytes proofData)`. +pub const SEAL_BYTES: usize = 1856; + +/// 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. +/// +/// The worker leads its own process group, and the deadline stops the whole group. A wrapper script +/// that starts the prover as a child, for example to set `LD_LIBRARY_PATH` for CUDA, therefore +/// cannot leave the prover running and holding the GPU. +async fn run_worker(worker: &Path, args: &[&OsStr], timeout: Duration, action: &str) -> Result<()> { + let mut command = tokio::process::Command::new(worker); + command.args(args).kill_on_drop(true); + #[cfg(unix)] + command.process_group(0); + let mut child = command + .spawn() + .with_context(|| format!("cannot start the OpenVM worker {}", worker.display()))?; + let mut group = WorkerGroup(child.id()); + match tokio::time::timeout(timeout, child.wait()).await { + Ok(status) => { + // The worker has exited and been reaped, so its id may be reused: stop tracking it. + group.0 = None; + let status = status.context("cannot wait for the OpenVM worker")?; + ensure!(status.success(), "OpenVM {action} failed ({status})"); + Ok(()) + } + Err(_) => { + group.stop(); + // `kill` also reaps the worker, 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() + ) + } + } +} + +/// The process group of a running worker. Dropping it, as a cancelled request does, stops the +/// whole group, not only the worker that `kill_on_drop` reaches. +struct WorkerGroup(Option); + +impl WorkerGroup { + fn stop(&mut self) { + #[cfg(unix)] + if let Some(id) = self.0.take() { + // The worker was started with `process_group(0)`, so its id is the group's id, and the + // group exists while the worker runs. The return value is ignored: an empty group is + // already stopped. + unsafe { + libc::killpg(id as libc::pid_t, libc::SIGKILL); + } + } + } +} + +impl Drop for WorkerGroup { + fn drop(&mut self) { + self.stop(); + } +} + +/// 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(), 1984); + 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. + /// + /// A child process writes it. Tests in this process fork while others run, and a forked child + /// keeps a copy of any file this process has open for writing until it executes. Executing the + /// script while such a copy is open fails with ETXTBSY. + #[cfg(unix)] + fn worker(directory: &Path, name: &str, body: &str) -> PathBuf { + let path = directory.join(name); + let status = std::process::Command::new("/bin/sh") + .args([ + "-c", + "printf '%s' \"$2\" > \"$1\" && chmod 755 \"$1\"", + "sh", + ]) + .arg(&path) + .arg(format!("#!/bin/sh\n{body}\n")) + .status() + .unwrap(); + assert!(status.success(), "cannot write the stand-in worker"); + 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)); + } + + /// A wrapper script that starts the prover as a child does not leave it running after the + /// deadline: the whole process group is stopped. + #[cfg(unix)] + #[tokio::test] + async fn the_deadline_also_stops_a_wrapper_scripts_prover() { + let directory = tempfile::tempdir().unwrap(); + let pid_file = directory.path().join("prover.pid"); + let script = directory.path().join("wrapper.sh"); + let body = format!("sleep 30 &\necho $! > {}\nwait\n", pid_file.display()); + fs::write(&script, body).unwrap(); + + // /bin/sh reads the script, so the test does not execute a file it has just written: + // that can fail with ETXTBSY while another test in this process forks. + let error = run_worker( + Path::new("/bin/sh"), + &[script.as_os_str()], + Duration::from_millis(500), + "proof generation", + ) + .await + .unwrap_err(); + assert!(error.to_string().contains("did not finish"), "{error}"); + + let pid: libc::pid_t = fs::read_to_string(&pid_file) + .unwrap() + .trim() + .parse() + .unwrap(); + let deadline = std::time::Instant::now() + Duration::from_secs(5); + // A stopped process can stay a zombie until init reaps it, so wait for it to disappear. + while unsafe { libc::kill(pid, 0) } == 0 { + assert!( + std::time::Instant::now() < deadline, + "the prover {pid} outlived its wrapper" + ); + tokio::time::sleep(Duration::from_millis(50)).await; + } + } +} diff --git a/crates/openvm-prover/Cargo.lock b/crates/openvm-prover/Cargo.lock new file mode 100644 index 0000000000..1af72142c3 --- /dev/null +++ b/crates/openvm-prover/Cargo.lock @@ -0,0 +1,6517 @@ +# 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-cuda-common", + "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/openvm-prover/Cargo.toml b/crates/openvm-prover/Cargo.toml new file mode 100644 index 0000000000..09242437de --- /dev/null +++ b/crates/openvm-prover/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "interfold-openvm-prover" +version = "0.1.0" +edition = "2021" +license = "LGPL-3.0-only" + +[workspace] +resolver = "3" + +[features] +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"] } +serde_json = "1" +hex = "0.4" diff --git a/crates/openvm-prover/README.md b/crates/openvm-prover/README.md new file mode 100644 index 0000000000..3c4d00dfdd --- /dev/null +++ b/crates/openvm-prover/README.md @@ -0,0 +1,203 @@ +# 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, and it stops at startup when it cannot open a GPU. Keep the two builds apart; a project +may configure both. On a machine without a GPU, configure the CPU worker: `compile` runs `prepare` +with it. + +## 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 +``` + +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 the worker configuration (`OPENVM_PROVER_CONFIG`, or +`.interfold/caches/openvm/prover.json`), and builds the service. `start` and the deploys read the +same path. 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 | +| `execute ` | Runs the guest without proving; checks the journal | +| `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 | +| `OPENVM_BODY_TIMEOUT_SECS` | 120 | Time an admitted request has to send its 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))`, 1,856 bytes. It does not repeat the +journal: the proof's only public value is the journal digest, which the contracts recompute. + +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/openvm-prover/src/main.rs b/crates/openvm-prover/src/main.rs new file mode 100644 index 0000000000..3488fdb765 --- /dev/null +++ b/crates/openvm-prover/src/main.rs @@ -0,0 +1,493 @@ +// 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. +//! - `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. + +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, + EVM_VERIFIER_ARTIFACT_FILENAME, + }, + halo2_params::CacheHalo2ParamsReader, + keygen::{AggProvingKey, AppProvingKey}, + prover::Halo2Prover, + types::{AppExecutionCommit, EvmHalo2Verifier, EvmProof}, + Sdk, StdIn, F, OPENVM_VERSION, +}; +use openvm_sdk_config::SdkVmConfig; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::{ + fs, + io::{BufReader, Read, Write}, + path::{Path, PathBuf}, +}; + +/// 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, + 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 validate(config: &Config) -> Result<()> { + 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: {}", + path.display() + ); + } + 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(()) +} + +fn config(path: &Path) -> Result { + let config: Config = serde_json::from_slice(&read_limited(path, 64 * 1024)?)?; + validate(&config)?; + 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 `abi.encode(uint8 version, bytes proofData)`. +/// +/// The proof's only public value is the journal digest, which the contract recomputes from chain +/// state and passes to the Halo2 verifier, so the seal does not repeat the journal. +fn seal(proof: &EvmProof) -> Vec { + encode_seal( + &[ + proof.proof_data.accumulator.as_slice(), + proof.proof_data.proof.as_slice(), + ] + .concat(), + ) +} + +/// `abi.encode(uint8(1), proofData)` for the 1,760 bytes of Halo2 proof data. No padding is needed: +/// the length is a multiple of 32. +fn encode_seal(proof_data: &[u8]) -> Vec { + let mut bytes = Vec::with_capacity(96 + proof_data.len()); + bytes.extend_from_slice(&word(1)); + bytes.extend_from_slice(&word(64)); + bytes.extend_from_slice(&word(proof_data.len())); + bytes.extend_from_slice(proof_data); + 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") +} + +/// 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())) +} + +/// 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, write-config, probe, check, execute, 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!( + 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)?; + // 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(()); + } + 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, execute, 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_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(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))?; + file.sync_all()?; + eprintln!("OpenVM: verified the proof, the application identity, and the journal digest"); + 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()); + } + + /// The seal is `abi.encode(uint8(1), proofData)`: the layout `OpenVmReceiptVerifier` decodes and + /// the 1,856 bytes `e3_openvm_host::SEAL_BYTES` expects. + #[test] + fn the_seal_is_the_abi_encoding_of_the_version_and_the_proof_data() { + let proof_data = [0xab; 1760]; + let seal = encode_seal(&proof_data); + + assert_eq!(seal.len(), 1856); + let mut head = [0u8; 96]; + head[31] = 1; + head[63] = 0x40; + head[94..96].copy_from_slice(&[0x06, 0xe0]); + assert_eq!(&seal[..96], head.as_slice()); + assert_eq!(&seal[96..], proof_data.as_slice()); + } + + #[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/Cargo.toml b/crates/program-server/Cargo.toml index db2b58d493..e7e95c2e28 100644 --- a/crates/program-server/Cargo.toml +++ b/crates/program-server/Cargo.toml @@ -8,6 +8,7 @@ repository.workspace = true [dependencies] actix-web.workspace = true +futures-util.workspace = true serde.workspace = true serde_json.workspace = true tokio.workspace = true diff --git a/crates/program-server/src/lib.rs b/crates/program-server/src/lib.rs index 51df53e62e..16a3db6563 100644 --- a/crates/program-server/src/lib.rs +++ b/crates/program-server/src/lib.rs @@ -87,6 +87,14 @@ 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; + +/// How long an admitted request may take to deliver its body. The request holds a compute slot +/// while it uploads, so a stalled upload must not keep it. +const DEFAULT_BODY_TIMEOUT: Duration = Duration::from_secs(120); + #[derive(Clone)] pub struct E3ProgramServerBuilder { runner: Arc, @@ -94,6 +102,8 @@ pub struct E3ProgramServerBuilder { host: Option, localhost_rewrite: Option, max_concurrent_jobs: usize, + max_request_bytes: usize, + body_timeout: Duration, } impl E3ProgramServerBuilder { @@ -109,6 +119,8 @@ impl E3ProgramServerBuilder { host: None, localhost_rewrite: None, max_concurrent_jobs: 1, + max_request_bytes: DEFAULT_MAX_REQUEST_BYTES, + body_timeout: DEFAULT_BODY_TIMEOUT, } } @@ -136,12 +148,34 @@ 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 + } + + /// Bound how long an admitted request may take to deliver its body (default 120 seconds). A + /// request that is still uploading holds a compute slot. + pub fn with_body_timeout(mut self, body_timeout: Duration) -> Self { + self.body_timeout = body_timeout; + 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" + ); + anyhow::ensure!( + !self.body_timeout.is_zero(), + "the request body timeout must be greater than zero" + ); let webhook_client = reqwest::Client::builder() .connect_timeout(Duration::from_secs(5)) .timeout(Duration::from_secs(30)) @@ -155,6 +189,8 @@ 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, + body_timeout: self.body_timeout, }) } } @@ -167,6 +203,8 @@ pub struct E3ProgramServer { localhost_rewrite: Option, webhook_client: reqwest::Client, jobs: Arc, + max_request_bytes: usize, + body_timeout: Duration, } impl E3ProgramServer { @@ -202,11 +240,12 @@ 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, + body_timeout: self.body_timeout, }; 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 +264,29 @@ pub struct AppConfig { pub localhost_rewrite: Option, webhook_client: reqwest::Client, jobs: Arc, + max_request_bytes: usize, + body_timeout: Duration, +} + +/// Reads an admitted request's body, refusing one over `limit` bytes (413) or one that does not +/// arrive within `timeout` (408). +async fn read_body(body: S, limit: usize, timeout: Duration) -> ActixResult +where + S: futures_util::Stream> + 'static, + E: Into> + 'static, +{ + let read = actix_web::body::to_bytes_limited(actix_web::body::BodyStream::new(body), limit); + match tokio::time::timeout(timeout, read).await { + Err(_) => Err(actix_web::error::ErrorRequestTimeout( + "the request body did not arrive in time", + )), + Ok(Err(exceeded)) => Err(actix_web::error::ErrorPayloadTooLarge(exceeded)), + Ok(Ok(Err(error))) => Err(actix_web::error::ErrorBadRequest(format!( + "cannot read the request body: {}", + error.into() + ))), + Ok(Ok(Ok(bytes))) => Ok(bytes), + } } /// Whether callbacks to addresses only reachable from inside the deployment are permitted. @@ -391,25 +453,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 +559,20 @@ 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 = read_body(body, config.max_request_bytes, config.body_timeout).await?; + 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 +656,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 +675,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(); @@ -671,6 +766,100 @@ mod server_tests { assert_eq!(server.jobs.available_permits(), 2); } + fn app_config(server: &E3ProgramServer) -> AppConfig { + AppConfig { + runner: Arc::clone(&server.runner), + localhost_rewrite: None, + webhook_client: server.webhook_client.clone(), + jobs: Arc::clone(&server.jobs), + max_request_bytes: server.max_request_bytes, + body_timeout: server.body_timeout, + } + } + + /// The handler applies the body deadline: a stalled upload is refused with 408 and gives its + /// slot back, so it cannot hold the server's capacity. + #[actix_web::test] + async fn a_stalled_upload_is_refused_and_frees_its_slot() { + use actix_web::FromRequest; + use std::pin::Pin; + + let server = E3ProgramServer::builder(|_| async { Ok((vec![], vec![])) }) + .with_body_timeout(Duration::from_millis(50)) + .build() + .unwrap(); + let stalled: Pin< + Box< + dyn futures_util::Stream>, + >, + > = Box::pin(futures_util::stream::pending()); + let mut payload = actix_web::dev::Payload::from(stalled); + let request = actix_web::test::TestRequest::post().to_http_request(); + let body = web::Payload::from_request(&request, &mut payload) + .await + .unwrap(); + + let error = tokio::time::timeout( + Duration::from_secs(10), + handle_compute(web::Data::new(app_config(&server)), body), + ) + .await + .expect("the handler must not wait past its body deadline") + .unwrap_err(); + + assert_eq!(error.as_response_error().status_code(), 408); + assert_eq!(server.jobs.available_permits(), 1); + } + + /// A caller over capacity is refused before its body is read, so it cannot make the server + /// buffer a round it will not compute. + #[actix_web::test] + async fn a_full_server_refuses_before_reading_the_body() { + let server = E3ProgramServer::builder(|_| async { Ok((vec![], vec![])) }) + .with_max_request_bytes(16) + .build() + .unwrap(); + let _busy = Arc::clone(&server.jobs).try_acquire_owned().unwrap(); + let app = actix_web::test::init_service( + App::new() + .app_data(web::Data::new(app_config(&server))) + .route("/run_compute", web::post().to(handle_compute)), + ) + .await; + + let request = actix_web::test::TestRequest::post() + .uri("/run_compute") + .set_payload(vec![b'x'; 1024]) + .to_request(); + let response = actix_web::test::call_service(&app, request).await; + + assert_eq!(response.status(), 429); + } + + /// With capacity free, a body over the limit is refused and the slot is released. + #[actix_web::test] + async fn an_oversized_body_is_refused_and_frees_its_slot() { + let server = E3ProgramServer::builder(|_| async { Ok((vec![], vec![])) }) + .with_max_request_bytes(16) + .build() + .unwrap(); + let app = actix_web::test::init_service( + App::new() + .app_data(web::Data::new(app_config(&server))) + .route("/run_compute", web::post().to(handle_compute)), + ) + .await; + + let request = actix_web::test::TestRequest::post() + .uri("/run_compute") + .set_payload(vec![b'x'; 1024]) + .to_request(); + let response = actix_web::test::call_service(&app, request).await; + + assert_eq!(response.status(), 413); + assert_eq!(server.jobs.available_permits(), 1); + } + #[test] fn localhost_rewrite_changes_only_an_exact_local_host() { let rewritten = 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..37a0e24c01 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 @@ -32,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/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/dev/compile b/crates/support-scripts/dev/compile index 1c849a8a26..d16bf339e5 100755 --- a/crates/support-scripts/dev/compile +++ b/crates/support-scripts/dev/compile @@ -1,3 +1,5 @@ #!/usr/bin/env bash -cargo build --locked --bin e3-support-scripts-dev +# Not --locked: `interfold init` points the project's Interfold crates at git, so the lock file a +# new project copies is out of date until cargo updates it. +cargo build --bin e3-support-scripts-dev diff --git a/crates/support-scripts/openvm/compile b/crates/support-scripts/openvm/compile new file mode 100755 index 0000000000..049111d7ef --- /dev/null +++ b/crates/support-scripts/openvm/compile @@ -0,0 +1,87 @@ +#!/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: OPENVM_PROVER_CONFIG, or .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, which +# works only where it can open a GPU +# 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_PROVER_CONFIG where to write the worker configuration; `start` and the template +# and CRISP deploys read the same path +# OPENVM_BUILD_LOCKED=1 build the guest with --locked (read by cargo-openvm) +set -euo pipefail + +PROJECT="$(pwd)" +GUEST="$PROJECT/guest" +OUT="$PROJECT/.interfold/caches/openvm" +CONFIG="${OPENVM_PROVER_CONFIG:-$OUT/prover.json}" +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 +if ! "${CARGO_OPENVM[@]}" --version >/dev/null 2>&1; then + echo "cargo-openvm is missing. Install it with: cargo install --locked --git" \ + "https://github.com/openvm-org/openvm.git --tag v2.0.2 cargo-openvm" >&2 + exit 1 +fi +if [ ! -f "$SETUP/halo2.pk" ] || [ ! -d "$SETUP/params" ]; then + echo "No Halo2 proving key and parameters in $SETUP. Run \`cargo openvm setup\`, or set" \ + "program.openvm.setup_dir to where they are." >&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" +# 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" + +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 "$CONFIG" "$KEYS/app.pk" "$EXE" "$PREPARED" "$SETUP" \ + "${OPENVM_SEGMENT_MEMORY_BYTES:-8589934592}" +echo "Worker configuration: $CONFIG" +echo "Receipt identity: $PREPARED/identity.json" + +# Not --locked: after `interfold init`, the project's lockfile still names the template's path +# sources until a build updates it. +echo "Building the OpenVM proving service" +cargo build --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..6ed8ae7b68 --- /dev/null +++ b/crates/support-scripts/openvm/service/src/main.rs @@ -0,0 +1,72 @@ +// 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; +use std::time::Duration; + +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)?) + .with_body_timeout(Duration::from_secs(env_or( + "OPENVM_BODY_TIMEOUT_SECS", + 120, + )?)) + .build()?; + + server.run().await +} diff --git a/crates/support-scripts/openvm/start b/crates/support-scripts/openvm/start new file mode 100755 index 0000000000..64be020476 --- /dev/null +++ b/crates/support-scripts/openvm/start @@ -0,0 +1,10 @@ +#!/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 is OPENVM_PROVER_CONFIG, or the one `compile` +# wrote. +set -euo pipefail + +export OPENVM_PROVER_CONFIG="${OPENVM_PROVER_CONFIG:-$(pwd)/.interfold/caches/openvm/prover.json}" +exec cargo run --release --bin e3-support-scripts-openvm diff --git a/crates/support-scripts/src/lib.rs b/crates/support-scripts/src/lib.rs index 241e6c8a1d..43f410fe6a 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,30 +16,17 @@ 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<()> { + 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 } -/// 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..89dc6b5cbd --- /dev/null +++ b/crates/support-scripts/src/program_openvm.rs @@ -0,0 +1,66 @@ +// 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::{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, script: &str) -> Result<()> { + let config = self.0.openvm().context( + "Set program.openvm.prover_bin to the CPU worker, program.openvm.prover_bin_cuda to \ + the CUDA worker, or both", + )?; + ensure!( + 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 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_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("compile").await + } + async fn start(&self) -> Result<()> { + self.run("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/.dockerignore b/crates/support/.dockerignore deleted file mode 100644 index 381cbeb22e..0000000000 --- a/crates/support/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/contracts -Elf.sol diff --git a/crates/support/Cargo.lock b/crates/support/Cargo.lock deleted file mode 100644 index 8f693c2053..0000000000 --- a/crates/support/Cargo.lock +++ /dev/null @@ -1,8471 +0,0 @@ -# This file is automatically @generated by Cargo. -# 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 2.10.0", - "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 0.22.1", - "bitflags 2.10.0", - "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.2", - "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" -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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -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" -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" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdff496dd4e98a81f4861e66f7eaf5f2488971848bb42d9c892f871730245c8" -dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-type-parser", - "alloy-sol-types", - "itoa", - "serde", - "serde_json", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" -dependencies = [ - "alloy-primitives", - "alloy-sol-type-parser", - "serde", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" -dependencies = [ - "alloy-rlp", - "bytes", - "cfg-if", - "const-hex", - "derive_more", - "foldhash 0.2.0", - "hashbrown 0.16.1", - "indexmap 2.12.1", - "itoa", - "k256", - "keccak-asm", - "paste", - "proptest", - "rand 0.9.2", - "ruint", - "rustc-hash", - "serde", - "sha3", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" -dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "alloy-sol-macro-expander" -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", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.119", - "syn-solidity", - "tiny-keccak", -] - -[[package]] -name = "alloy-sol-macro-input" -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", -] - -[[package]] -name = "alloy-sol-type-parser" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" -dependencies = [ - "serde", - "winnow", -] - -[[package]] -name = "alloy-sol-types" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70319350969a3af119da6fb3e9bddb1bce66c9ea933600cb297c8b1850ad2a3c" -dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-macro", - "serde", -] - -[[package]] -name = "alloy-transport" -version = "1.0.41" -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" -dependencies = [ - "anstyle", - "anstyle-parse 0.2.7", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse 1.0.0", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[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 0.61.2", -] - -[[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 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" -dependencies = [ - "ark-ec 0.4.2", - "ark-ff 0.4.2", - "ark-std 0.4.0", -] - -[[package]] -name = "ark-bn254" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -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]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff 0.4.2", - "ark-poly 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[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 0.5.0", - "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-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-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-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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", -] - -[[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 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" -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-serialize-derive 0.4.2", - "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-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[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-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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "num-traits", - "rand 0.8.6", -] - -[[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.6", -] - -[[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.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" -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", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -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", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "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", -] - -[[package]] -name = "async-object-pool" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333c456b97c3f2d50604e8b2624253b7f787208cb72eb75e64b0ad11b221652c" -dependencies = [ - "async-std", -] - -[[package]] -name = "async-process" -version = "2.5.0" -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", -] - -[[package]] -name = "async-signal" -version = "0.2.13" -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", -] - -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -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", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[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" -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", -] - -[[package]] -name = "brotli" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[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.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" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream 1.0.0", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "clap_lex" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" -dependencies = [ - "cfg-if", - "cpufeatures", - "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.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" -dependencies = [ - "const_format_proc_macros", -] - -[[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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[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.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" -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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", - "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_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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" -dependencies = [ - "proc-macro2", - "quote", - "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", - "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", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "doc-comment" -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" -dependencies = [ - "anyhow", - "e3-fhe-params", - "e3-polynomial", - "e3-zk-helpers", - "fhe", - "fhe-traits", - "rand 0.9.2", - "thiserror 1.0.69", -] - -[[package]] -name = "e3-compute-provider" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" -dependencies = [ - "ark-bn254 0.4.0", - "ark-ff 0.4.2", - "e3-bfv-client", - "e3-fhe-params", - "fhe", - "hex", - "lean-imt", - "light-poseidon", - "num-bigint", - "num-traits", - "serde", - "sha2", - "sha3", - "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" -dependencies = [ - "alloy-dyn-abi", - "alloy-primitives", - "anyhow", - "clap", - "fhe", - "num-bigint", - "num-traits", - "rand 0.9.2", - "rand_chacha 0.9.0", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "e3-parity-matrix" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" -dependencies = [ - "num-bigint", - "num-traits", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "e3-polynomial" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" -dependencies = [ - "fhe-math", - "num-bigint", - "num-traits", - "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "e3-safe" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" -dependencies = [ - "ark-bn254 0.5.0", - "ark-ff 0.5.0", - "hex", - "risc0-bigint2", - "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-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", - "tokio", - "tracing-subscriber 0.3.20", - "url", -] - -[[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" -dependencies = [ - "e3-compute-provider", - "e3-fhe-params", - "fhe", - "fhe-traits", - "sha2", - "sha3", -] - -[[package]] -name = "e3-zk-helpers" -version = "0.14.0" -source = "git+https://github.com/theinterfold/interfold?rev=5668f4c9ee0992aeb05b320eaa3b998a6c32e525#5668f4c9ee0992aeb05b320eaa3b998a6c32e525" -dependencies = [ - "anyhow", - "ark-bn254 0.5.0", - "ark-ff 0.5.0", - "clap", - "e3-fhe-params", - "e3-parity-matrix", - "e3-polynomial", - "e3-safe", - "fhe", - "fhe-math", - "fhe-traits", - "hex", - "itertools 0.14.0", - "ndarray", - "num-bigint", - "num-integer", - "num-traits", - "rand 0.9.2", - "rayon", - "serde", - "serde_json", - "thiserror 1.0.69", - "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", - "digest 0.10.7", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "serdect", - "signature 2.2.0", - "spki 0.7.3", -] - -[[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.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" -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", - "digest 0.10.7", - "ff 0.13.1", - "generic-array", - "group 0.13.0", - "pkcs8 0.10.2", - "rand_core 0.6.4", - "sec1 0.7.3", - "serdect", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[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" -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", -] - -[[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" -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 0.61.2", -] - -[[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" -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", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[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 = [ - "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 = [ - "rand_core 0.6.4", - "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", - "fhe-traits", - "fhe-util", - "itertools 0.14.0", - "ndarray", - "num-bigint", - "num-traits", - "prost 0.14.4", - "prost-build", - "rand 0.9.2", - "rand_chacha 0.9.0", - "rand_distr", - "rayon", - "serde", - "thiserror 2.0.18", - "zeroize", - "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", - "fhe-util", - "itertools 0.14.0", - "ndarray", - "num-bigint", - "num-bigint-dig 0.9.1", - "num-traits", - "prost 0.14.4", - "prost-build", - "pulp", - "rand 0.9.2", - "rand_chacha 0.9.0", - "serde", - "sha2", - "tfhe-ntt", - "thiserror 2.0.18", - "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", -] - -[[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 0.9.1", - "num-traits", - "prime_factorization", - "rand 0.8.6", - "rand 0.9.2", - "rand_distr", - "rayon", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" - -[[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.6", - "rustc-hex", - "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" -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" -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 = "foreign-types" -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", -] - -[[package]] -name = "foreign-types-shared" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "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_core 0.6.4", - "subtle", -] - -[[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 2.12.1", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.4.0", - "indexmap 2.12.1", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -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" -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.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "foldhash 0.2.0", - "serde", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.4.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.4.0", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2 0.4.12", - "http 1.4.0", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http 1.4.0", - "hyper 1.8.1", - "hyper-util", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.8.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.1", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "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" -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 = "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" -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 = "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" -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 2.10.0", - "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.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.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jiff" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", -] - -[[package]] -name = "jiff-static" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "once_cell", - "serdect", - "sha2", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "keccak-asm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" -dependencies = [ - "digest 0.10.7", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2acc6dee32b12409446a76b9c1877e5ba9afb36dfcbe96d0ddaf15ca08f18d" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "libm" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" -dependencies = [ - "ark-bn254 0.4.0", - "ark-ff 0.4.2", - "num-bigint", - "thiserror 1.0.69", -] - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[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" -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", -] - -[[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.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "maybe-async" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest 0.10.7", -] - -[[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" -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" -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", -] - -[[package]] -name = "multimap" -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 2.11.1", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndarray" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" -dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "portable-atomic", - "portable-atomic-util", - "rawpointer", - "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-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.8.6", - "serde", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-bigint-dig" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f9a86e097b0d187ad0e65667c2f58b9254671e86e7dbb78036b16692eae099" -dependencies = [ - "libm", - "num-integer", - "num-iter", - "num-traits", - "once_cell", - "rand 0.9.2", - "serde", - "smallvec", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "bytemuck", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-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.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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -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" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "outref" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" - -[[package]] -name = "p256" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" -dependencies = [ - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2", -] - -[[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", - "proc-macro2", - "quote", - "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" -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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pest" -version = "2.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" -dependencies = [ - "memchr", - "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", - "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", -] - -[[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" -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", -] - -[[package]] -name = "pkg-config" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.119", -] - -[[package]] -name = "prime_factorization" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb24cb4f70d64221509ab3dca82ad2ec24e1d7f3fa3e7cb9eed4ced578683287" -dependencies = [ - "itertools 0.10.5", - "num", - "rand 0.8.6", -] - -[[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 = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit 0.23.7", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "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 = "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", - "num-traits", - "rand 0.9.2", - "rand_chacha 0.9.0", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" -dependencies = [ - "bytes", - "prost-derive 0.14.4", -] - -[[package]] -name = "prost-build" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" -dependencies = [ - "heck", - "itertools 0.14.0", - "log", - "multimap", - "petgraph 0.8.3", - "prettyplease", - "prost 0.14.4", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "prost-types" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" -dependencies = [ - "prost 0.14.4", -] - -[[package]] -name = "pulp" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632" -dependencies = [ - "bytemuck", - "cfg-if", - "libm", - "num-complex", - "paste", - "pulp-wasm-simd-flag", - "raw-cpuid", - "reborrow", - "version_check", -] - -[[package]] -name = "pulp-wasm-simd-flag" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0" - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quinn" -version = "0.11.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" -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 = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "serde", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", - "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.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.4", - "serde", -] - -[[package]] -name = "rand_distr" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" -dependencies = [ - "num-traits", - "rand 0.9.2", -] - -[[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.3", -] - -[[package]] -name = "raw-cpuid" -version = "11.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" -dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "reborrow" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" - -[[package]] -name = "redox_syscall" -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", -] - -[[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-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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.4.12", - "http 1.4.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", - "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", - "serde_urlencoded", - "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]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.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", -] - -[[package]] -name = "risc0-zkvm-platform" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaa10feba15828c788837ddde84b994393936d8f5715228627cfe8625122a40" -dependencies = [ - "bytemuck", - "cfg-if", - "getrandom 0.2.16", - "getrandom 0.3.4", - "libm", - "num_enum", - "paste", - "stability", -] - -[[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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" -dependencies = [ - "alloy-rlp", - "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-integer", - "num-traits", - "parity-scale-codec", - "primitive-types", - "proptest", - "rand 0.8.6", - "rand 0.9.2", - "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.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[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.27", -] - -[[package]] -name = "rustix" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" -dependencies = [ - "bitflags 2.10.0", - "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", - "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", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "rusty-fork" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" -dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", -] - -[[package]] -name = "ryu" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -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", - "generic-array", - "pkcs8 0.10.2", - "serdect", - "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", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -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" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - -[[package]] -name = "sha3-asm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" -dependencies = [ - "cc", - "cfg-if", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest 0.10.7", - "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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - -[[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", -] - -[[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" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "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-solidity" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" -dependencies = [ - "paste", - "proc-macro2", - "quote", - "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 2.10.0", - "core-foundation 0.9.4", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac59d3df4c827b3496bff929aebd6440997a5c2e946f46ff4fdd76f318447581" -dependencies = [ - "ark-bn254 0.5.0", - "ark-ff 0.5.0", - "ark-std 0.5.0", - "num-bigint", - "num-traits", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" -dependencies = [ - "fastrand", - "getrandom 0.3.4", - "once_cell", - "rustix", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10650c743ade46b166c698c8349902ed5986784a7db418c51f810bea25f09e3d" -dependencies = [ - "aligned-vec", - "bytemuck", - "pulp", -] - -[[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.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[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.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -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", -] - -[[package]] -name = "time" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -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 = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "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" -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.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", - "tokio", - "tokio-native-tls", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[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 = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.12.1", - "serde", - "serde_spanned", - "toml_datetime 0.6.11", - "toml_write", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" -dependencies = [ - "indexmap 2.12.1", - "toml_datetime 0.7.3", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_parser" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" -dependencies = [ - "winnow", -] - -[[package]] -name = "toml_write" -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 2.10.0", - "bytes", - "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "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", - "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]] -name = "try-lock" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[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 = "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" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" -dependencies = [ - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.119", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[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.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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -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", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -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" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a40d2f9afd345a14a304ad2ced6dbff4c17a0e5c533a3bd5f64fd04dcb2531" -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/crates/support/Cargo.toml b/crates/support/Cargo.toml deleted file mode 100644 index 1a364e3328..0000000000 --- a/crates/support/Cargo.toml +++ /dev/null @@ -1,77 +0,0 @@ -[workspace] -resolver = "3" -msrv = "1.91.1" -members = ["app", "host", "methods", "types"] -exclude = ["methods/guest"] - -[workspace.package] -version = "0.1.0" -edition = "2021" - -[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" } - -methods = { path = "./methods" } -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"] } -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. -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" } -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" } - -[profile.release] -debug = 1 -lto = true diff --git a/crates/support/Dockerfile b/crates/support/Dockerfile index 53aa28420c..ab326c715d 100644 --- a/crates/support/Dockerfile +++ b/crates/support/Dockerfile @@ -1,69 +1,19 @@ 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"] +# 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 +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 ["./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 066d49b7de..0000000000 --- a/crates/support/README.md +++ /dev/null @@ -1,373 +0,0 @@ -# E3 Support — RISC Zero + Boundless Compute Provider - -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. - -```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)"] - - 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:** - -```json -{ "status": "failed", "e3_id": "123", "error": "Computation failed: ..." } -``` - -This matches the format expected by CRISP and `E3ProgramServer` in `crates/program-server`. - ---- - -## Full E3 Flow — Step by Step - -### Prerequisites - -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. - -### Step 1: Configure `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 -``` - -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: - -```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 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: - -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` - -### Step 7: Encrypt Inputs & Submit to Compute Provider - -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 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`. - -### Step 9: Decryption & Completion - -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. - ---- - -## Boundless Offer Parameters - -`build_offer()` reads these environment variables. Defaults: - -| 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 -``` - -Inside the container: - -```bash -cargo build --locked -cargo run --bin e3-support-app -``` - -## Testing - -```bash -cargo test --manifest-path host/Cargo.toml -``` - -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. - -**NOTE: currently this is an open relay which is a known issue** diff --git a/crates/support/app/Cargo.toml b/crates/support/app/Cargo.toml deleted file mode 100644 index 2a14b4dd3f..0000000000 --- a/crates/support/app/Cargo.toml +++ /dev/null @@ -1,24 +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 -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 deleted file mode 100644 index 0dc9f04386..0000000000 --- a/crates/support/app/src/main.rs +++ /dev/null @@ -1,460 +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?; - - 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)) - } - } -} - -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. 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. -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(()); - } - - // 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. - 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, loopback 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, blocking workers and Boundless submissions 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)?; - - println!("fhe_inputs.params = {:?}", fhe_inputs.params); - let callback_url = callback_url - .replace("localhost", "host.local") - .replace("127.0.0.1", "host.local"); - - // 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(); - let bind_addr = "0.0.0.0:13151"; - let server = HttpServer::new(move || { - App::new() - .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 8315f5bedd..0000000000 --- a/crates/support/host/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "e3-support-host" -version = { workspace = true } -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"] } - -[dev-dependencies] -hex = { workspace = true } diff --git a/crates/support/host/README.md b/crates/support/host/README.md deleted file mode 100644 index afa5583b4b..0000000000 --- a/crates/support/host/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Risc0 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. 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 deleted file mode 100644 index 5abf1f77ef..0000000000 --- a/crates/support/host/src/lib.rs +++ /dev/null @@ -1,833 +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::{ - utils::{parse_ether, parse_units}, - Bytes, B256, -}; -use alloy_signer_local::PrivateKeySigner; -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 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; - -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 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, - } - } -} - -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, - ); - - // 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 - ); - - // 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())?) -} - -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(), - )); - } - 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 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()) - ); - } - - #[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], - }], - }, - }; - - 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( - 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(), - }, - ) - .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" - ); - } - - #[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)); - } -} 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/program/Cargo.toml b/crates/support/program/Cargo.toml deleted file mode 100644 index bdff075e30..0000000000 --- a/crates/support/program/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "e3-user-program" -version = "0.1.0" -edition = "2024" - -[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 } 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/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 deleted file mode 100755 index 701adb0f20..0000000000 --- a/crates/support/scripts/container/build.sh +++ /dev/null @@ -1 +0,0 @@ -cargo build --locked diff --git a/crates/support/scripts/container/start.sh b/crates/support/scripts/container/start.sh deleted file mode 100755 index 5c4fd7a64d..0000000000 --- a/crates/support/scripts/container/start.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/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 "$@" 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/tests/.keep b/crates/support/tests/.keep deleted file mode 100644 index e69de29bb2..0000000000 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 4f95044177..0000000000 --- a/crates/support/types/src/lib.rs +++ /dev/null @@ -1,360 +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 { - 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/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..6d0ee4ec62 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.is_multiple_of(2) { + 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 = [ + -&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/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..6c91a3e890 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 @@ -379,7 +356,7 @@ These scripts are defined in `examples/CRISP/package.json`. | `pnpm compute:vk-hash` | Compiles the circuits and prints the fold key hash for each ballot stack | | `pnpm compile:contracts` | Compiles the CRISP contracts with Hardhat | | `pnpm build:sdk`, `pnpm build:presets` | Builds the SDK, or compiles and stages the circuit presets | -| `pnpm deploy:contracts`, `pnpm deploy:contracts:mock`, `pnpm deploy:contracts:full`, `pnpm deploy:contracts:full:mock` | Deploys the CRISP contracts. `mock` sets `USE_MOCKS=true`. `full` also deploys the Interfold contracts. | +| `pnpm deploy:contracts`, `pnpm deploy:contracts:mock`, `pnpm deploy:contracts:full`, `pnpm deploy:contracts:full:mock` | Deploys the CRISP contracts. `mock` sets `USE_MOCKS=true`, which mocks the token and data availability, not compute. `full` adds the Interfold contracts. | | `pnpm ciphernode:add`, `pnpm ciphernode:add:self`, `pnpm ciphernode:mint:tokens` | Hardhat tasks that register ciphernodes or mint tokens for them | | `pnpm setup:testnet` | Starts `cn1` to `cn5`, mints tokens for them, and registers them on Sepolia with the keys in `.env`. Then it starts the program server and the CRISP server. | | `pnpm publish:packages` | Publishes the CRISP packages to npm (`--channel prod` or `--channel testing`) | @@ -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..ef9e3cbed6 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,59 @@ 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 guest build swaps in OpenVM's +accelerated hashing, so the prediction holds only while that code matches the host's. Check it by +running the guest without proving: the worker's `execute` compares the digest it reveals with the +host's journal. + +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 +107,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 +132,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 +142,19 @@ 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 | +| Body deadline | 120 s | 120 s; set `OPENVM_BODY_TIMEOUT_SECS` 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, a body +over the limit gets HTTP 413, and a body that does not arrive by the deadline gets HTTP 408. The +webhook is retried with backoff after a network error or HTTP 5xx, 408, or 429. ### Request fields @@ -168,22 +212,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 +236,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))`, 1,856 bytes. It does not repeat the journal: +the Halo2 proof's only public value is the journal digest. `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` | +| `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 the worker configuration +to `.interfold/caches/openvm/prover.json` (or to `OPENVM_PROVER_CONFIG` when it is set; `start` and +the deploys read the same path), 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 +348,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 +368,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, tag `v0.4.2`), `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 `v0.4.2`) | 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..c367ca878d 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,23 @@ 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, 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 +59,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 +68,45 @@ 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 -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. +An E3 program can keep its own identity and receipt verifier. The template sets them in the +constructor and has no setter. `CRISPProgram` has `setOpenVmVerifier`, which only its owner can call +and which takes the new verifier's identity with it. Every constructor here refuses an identity that +its receipt verifier does not report. A change of verifier 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 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,39 +119,39 @@ 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 -``` - -Make sure that this address is the RISC Zero verifier that you expect for this chain. - -### Compare with the source +### Compare with the guest -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 --project --config --prover \ + --rpc --verifier --out manifest.json ``` +`--project` is the project whose guest the worker configuration describes. It defaults to +`examples/CRISP`. + Make sure that the manifest shows `"complete": true`. The `unresolved` list names each field that the script did not resolve. @@ -146,41 +159,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 and the project's commit, whether both are clean, and the digests of the root + and worker lockfiles, the project's lockfile, the guest 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 +190,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..f999381023 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,7 +222,7 @@ 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`, +The template uses the `fhe` crate from `gnosisguild/fhe.rs` at tag `v0.4.2`. 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/custom-zk-circuits.mdx b/docs/pages/build/tutorials/custom-zk-circuits.mdx index e7bf51d57d..9de6ecf16a 100644 --- a/docs/pages/build/tutorials/custom-zk-circuits.mdx +++ b/docs/pages/build/tutorials/custom-zk-circuits.mdx @@ -344,7 +344,7 @@ contract MyProgram is IE3Program, IE3ProgramDataAvailability, IERC165, Ownable { constructor( IInterfold _interfold, - IRiscZeroVerifier _verifier, + IOpenVmReceiptVerifier _verifier, ICircuitVerifier _inputVerifier, bytes32 _imageId ) Ownable(msg.sender) { 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