diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 00000000..c91c3f38
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,2 @@
+[net]
+git-fetch-with-cli = true
diff --git a/.github/actions/install-solc/action.yml b/.github/actions/install-solc/action.yml
new file mode 100644
index 00000000..eb5f8301
--- /dev/null
+++ b/.github/actions/install-solc/action.yml
@@ -0,0 +1,23 @@
+---
+name: 'Install Solc'
+description: 'Installs the Solc compiler.'
+inputs:
+ solc-version:
+ description: 'The latest version of solc.'
+ required: false
+ default: '0.8.26'
+runs:
+ using: "composite"
+ steps:
+ - name: Install solc compiler
+ shell: bash
+ run: |
+ if ! solc --version &> /dev/null ||
+ [[ $(solc --version | grep -oP '(\d+\.\d+\.\d+)' | head -n 1) \
+ != ${{ inputs.solc-version }} ]]; then
+ cargo install solc-select --force
+ solc-select install ${{ inputs.solc-version }}
+ solc-select use ${{ inputs.solc-version }}
+ else
+ echo "solc is already installed."
+ fi
diff --git a/.github/actions/prepare-rust-env/action.yml b/.github/actions/prepare-rust-env/action.yml
new file mode 100644
index 00000000..089dce21
--- /dev/null
+++ b/.github/actions/prepare-rust-env/action.yml
@@ -0,0 +1,29 @@
+---
+name: 'Prepare Rust environment'
+description: >
+ Installs Rust toolchain, authenticates with SSH (in order to access Github private repos)
+inputs:
+ poseidon-gadget-private-key:
+ description: 'SSH private key that corresponds to the deploy key in poseidon2-gadget repository'
+ required: true
+ zkos-circuits-private-key:
+ description: 'SSH private key that corresponds to the deploy key in zkos-circuits repository'
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: |
+ ${{ inputs.poseidon-gadget-private-key }}
+ ${{ inputs.zkos-circuits-private-key }}
+
+ - name: Install Rust toolchain
+ uses: Cardinal-Cryptography/github-actions/install-rust-toolchain@v7
+ with:
+ channel: nightly
+
+ - name: Install sccache
+ shell: bash
+ run: scripts/install-sccache
diff --git a/.github/actions/shielder-relayer/build-and-push/action.yml b/.github/actions/shielder-relayer/build-and-push/action.yml
new file mode 100644
index 00000000..f71b92a7
--- /dev/null
+++ b/.github/actions/shielder-relayer/build-and-push/action.yml
@@ -0,0 +1,56 @@
+---
+name: Build and push docker image
+
+inputs:
+ aws-mainnet-ecr-access-key:
+ required: true
+ aws-mainnet-ecr-access-key-id:
+ required: true
+ ecr-private-host:
+ description: ECR private host
+ required: true
+
+outputs:
+ image_tag:
+ description: Tag of the pushed image
+ value: ${{ steps.outputs.outputs.image_tag }}
+
+runs:
+ using: composite
+ steps:
+ - name: Call action get-ref-properties
+ id: get-ref-properties
+ uses: Cardinal-Cryptography/github-actions/get-ref-properties@v6
+
+ - name: DOCKER | Login to private Amazon ECR
+ id: login-private-ecr
+ uses: docker/login-action@v2
+ with:
+ registry: ${{ inputs.ecr-private-host }}
+ username: ${{ inputs.aws-mainnet-ecr-access-key-id }}
+ password: ${{ inputs.aws-mainnet-ecr-access-key }}
+ env:
+ AWS_REGION: us-east-1
+
+ - name: DOCKER | Docker Buildx
+ id: buildx
+ uses: docker/setup-buildx-action@v2
+ with:
+ version: v0.9.1
+
+ - name: DOCKER | Build and push latest docker image
+ id: build-image
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ builder: ${{ steps.buildx.outputs.name }}
+ file: ./crates/shielder-relayer/docker/Dockerfile
+ push: true
+ tags: "${{ inputs.ecr-private-host }}/shielder-relayer:\
+ ${{ steps.get-ref-properties.outputs.sha }}"
+
+ - name: OUTPUTS | Set output with docker image
+ id: outputs
+ shell: bash
+ run: |
+ echo "image_tag=${{ steps.get-ref-properties.outputs.sha }}" >> $GITHUB_OUTPUT
diff --git a/.github/actions/shielder-relayer/deploy/action.yml b/.github/actions/shielder-relayer/deploy/action.yml
new file mode 100644
index 00000000..74d0c1f1
--- /dev/null
+++ b/.github/actions/shielder-relayer/deploy/action.yml
@@ -0,0 +1,66 @@
+---
+name: Deploy docker image
+
+inputs:
+ image-tag:
+ description: Tag of the docker image to be deployed
+ required: true
+ autocommit-author:
+ description: Commit author
+ required: true
+ autocommit-email:
+ description: Commit author's mail
+ required: true
+ github-token:
+ description: Github token
+ required: true
+ ecr-private-host:
+ description: ECR private host
+ required: true
+ kustomize-version:
+ description: Kustomize version
+ required: true
+ environment:
+ type: choice
+ options:
+ - testnet-dev
+ - testnet
+ - mainnet
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: GIT | Checkout aleph-apps repo
+ uses: actions/checkout@v4
+ with:
+ repository: Cardinal-Cryptography/aleph-apps
+ token: ${{ inputs.github-token }}
+ path: "aleph-apps"
+ ref: main
+
+ - name: KUSTOMIZE | Init kustomize
+ uses: imranismail/setup-kustomize@v2
+ with:
+ kustomize-version: ${{ inputs.kustomize-version }}
+
+ - name: KUSTOMIZE | Update docker image tag
+ shell: bash
+ env:
+ DEPLOY_IMAGE: ${{ inputs.ecr-private-host }}/shielder-relayer:${{ inputs.image-tag }}
+ run: |
+ cd aleph-apps/shielder-relayer/overlays/${{ inputs.environment }}/eu-central-1
+ kustomize edit set image "shielder-relayer-image-placeholder=${{ env.DEPLOY_IMAGE }}"
+
+ - name: GIT | Commit changes to aleph-apps repository
+ uses: EndBug/add-and-commit@v9.1.4
+ env:
+ GITHUB_TOKEN: ${{ inputs.github-token }}
+ with:
+ author_name: ${{ inputs.autocommit-author }}
+ author_email: ${{ inputs.autocommit-email }}
+ message: >
+ Updating shielder-relayer ${{ inputs.environment }}
+ docker image tag: ${{ inputs.image-tag }}
+ add: "*.yaml"
+ cwd: 'aleph-apps'
diff --git a/.github/workflows/_build-contracts.yml b/.github/workflows/_build-contracts.yml
new file mode 100644
index 00000000..2630fcd6
--- /dev/null
+++ b/.github/workflows/_build-contracts.yml
@@ -0,0 +1,60 @@
+---
+name: Generate, compile and lint contracts
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ main:
+ name: Generate, compile and lint contracts
+ runs-on: [self-hosted, Linux, X64, large]
+ #runs-on: ubuntu-20.04
+ timeout-minutes: 10
+
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Setup node
+ uses: asdf-vm/actions/install@v3
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Lint contracts code (excluding generated code)
+ shell: bash
+ run: make deps && make lint-contracts
+
+ - name: Regenerate verifier and Poseidon contracts and ensure that they are up-to-date
+ run: |
+ make generate-verifier-contracts && make generate-poseidon-contracts && \
+ git diff --exit-code -- contracts/
+
+ - name: Compile eth contracts
+ run: make compile-contracts
+
+ - name: Upload generated contracts to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: generated-contracts
+ path: contracts
+ retention-days: 1
+
+ - name: Upload bytecode and ABI to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+ retention-days: 1
diff --git a/.github/workflows/_build-wasm-packages.yml b/.github/workflows/_build-wasm-packages.yml
new file mode 100644
index 00000000..c62d9e89
--- /dev/null
+++ b/.github/workflows/_build-wasm-packages.yml
@@ -0,0 +1,35 @@
+---
+name: Build wasm packages
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ main:
+ name: Build wasm packages
+ runs-on: [self-hosted, Linux, X64, large]
+ timeout-minutes: 10
+
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Install wasm-pack
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+
+ - name: Build shielder-wasm
+ run: cd crates/shielder-wasm && make all
+
+ - name: Upload generated wasm to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: crates-shielder-wasm-pkg
+ path: crates/shielder-wasm/pkg
+ retention-days: 1
diff --git a/.github/workflows/_check-vars-and-secrets.yml b/.github/workflows/_check-vars-and-secrets.yml
new file mode 100644
index 00000000..3f7050f4
--- /dev/null
+++ b/.github/workflows/_check-vars-and-secrets.yml
@@ -0,0 +1,55 @@
+---
+# This workflow checks if vars and secrets are present and fails if one is empty.
+# It should be included as a first step in all the workflows.
+name: Check vars and secrets
+on:
+ workflow_call:
+
+jobs:
+ main:
+ name: Check available vars and secrets
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Check vars
+ run: |
+ if [[ \
+ -z '${{ vars.SHIELDER_CONTRACT_ADDRESS }}' || \
+ -z '${{ vars.KUSTOMIZE_VERSION }}' || \
+ -z '${{ vars.CI_TESTNET_ALICE_PUBLIC_KEY }} }}' || \
+ -z '${{ vars.CI_TESTNET_BOB_PUBLIC_KEY }} }}' || \
+ -z '${{ vars.CI_TESTNET_CHARLIE_PUBLIC_KEY }} }}' || \
+ -z '${{ vars.CI_TESTNET_RELAYER_SIGNER_ADDRESSES }} }}' || \
+ -z '${{ vars.CI_TESTNET_FEE_DESTINATION }} }}'
+ ]]; then
+ echo '!!! Some repository variables are either missing or empty.'
+ echo '!!! Please check either repository or organization settings.'
+ exit 1
+ fi
+
+ - name: Check secrets
+ run: |
+ if [[ \
+ -z '${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}' || \
+ -z '${{ secrets.SSH_PRIVATE_KEY }}' || \
+ -z '${{ secrets.VERCEL_ORG_ID }}' || \
+ -z '${{ secrets.VERCEL_PROJECT_ID }}' || \
+ -z '${{ secrets.VERCEL_TOKEN }}' || \
+ -z '${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }}' || \
+ -z '${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }}' || \
+ -z '${{ secrets.ECR_PRIVATE_HOST }}' || \
+ -z '${{ secrets.AUTOCOMMIT_AUTHOR }}' || \
+ -z '${{ secrets.AUTOCOMMIT_EMAIL }}' || \
+ -z '${{ secrets.CI_GH_TOKEN }}' || \
+ -z '${{ secrets.SLACK_WEBHOOK_ZKOS }}' || \
+ -z '${{ secrets.CI_TESTNET_DEPLOYER_PRIVATE_KEY }}' || \
+ -z '${{ secrets.CI_TESTNET_ALICE_PRIVATE_KEY }}' || \
+ -z '${{ secrets.CI_TESTNET_BOB_PRIVATE_KEY }}' || \
+ -z '${{ secrets.CI_TESTNET_CHARLIE_PRIVATE_KEY }}' || \
+ -z '${{ secrets.CI_TESTNET_FEE_DESTINATION_KEY }}' || \
+ -z '${{ secrets.CI_TESTNET_RELAYER_SIGNING_KEYS }}' || \
+ -z '${{ secrets.NPM_PUBLISHING_KEY }}'
+ ]]; then
+ echo '!!! Some repository secrets are either missing or empty.'
+ echo '!!! Please check either repository or organization settings.'
+ exit 1
+ fi
diff --git a/.github/workflows/_deploy-contracts.yml b/.github/workflows/_deploy-contracts.yml
new file mode 100644
index 00000000..f7c407bf
--- /dev/null
+++ b/.github/workflows/_deploy-contracts.yml
@@ -0,0 +1,51 @@
+---
+name: Deploy contracts
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ main:
+ name: Deploy contracts to the anvil network
+ runs-on: ubuntu-22.04
+ timeout-minutes: 10
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup node
+ uses: asdf-vm/actions/install@v3
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Run anvil node in background
+ shell: bash
+ run: make anvil &
+
+ - name: Install dependencies
+ shell: bash
+ run: make deps
+
+ - name: Download generated contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: generated-contracts
+ path: contracts
+
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+
+ - name: deploy eth contracts
+ shell: bash
+ run: NETWORK=anvil make deploy-contracts
diff --git a/.github/workflows/_rust-crates-checks.yml b/.github/workflows/_rust-crates-checks.yml
new file mode 100644
index 00000000..a905b478
--- /dev/null
+++ b/.github/workflows/_rust-crates-checks.yml
@@ -0,0 +1,110 @@
+---
+name: Run linter and tests for all Rust crates
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ # Run formatter and linter for all crates, and unit tests for all simple crates, that,
+ # in particular, do not require anvil node to be running.
+ # For shielder-circuit crate, we run tests and build the binary for measuring circuits.
+ rust-checks-and-unit-tests:
+ name: Run lints and tests
+ runs-on: [self-hosted, Linux, X64, large]
+ timeout-minutes: 60
+ env:
+ RUSTC_WRAPPER: sccache
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Download generated contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: generated-contracts
+ path: contracts
+
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ # NOTE: integration tests use vanilla solc compiler for compiling Solidity
+ - name: Install solc compiler
+ uses: ./.github/actions/install-solc
+ with:
+ solc-version: 0.8.26
+
+ - name: Run linter
+ run: |
+ make lint-rust
+ make format-rust
+
+ - name: Run tests for Shielder Rust SDK
+ run: cargo test --release -p shielder-rust-sdk --all-features
+
+ - name: Run tests for halo2-verifier
+ run: cd crates/halo2-verifier && make test
+
+ - name: Run tests for shielder-cli
+ run: cd crates/shielder-cli && make test
+
+ - name: Run tests for shielder-wasm
+ run: cd crates/shielder-wasm && make test
+
+ - name: Run integration tests
+ run: make deps && cargo test --release -p integration-tests
+
+ # Run heavy tests for shielder-relayer and e2e tooling tests.
+ full-testing:
+ name: Run heavy tests
+ runs-on: [self-hosted, Linux, X64, large]
+ timeout-minutes: 60
+ env:
+ RUSTC_WRAPPER: sccache
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Download generated contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: generated-contracts
+ path: contracts
+
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Run tests for shielder-relayer
+ run: make deps && cd crates/shielder-relayer && BUILD=client make test
+
+ - name: Run e2e tooling tests
+ run: |
+ NO_FORMATTING=true ./tooling-e2e-tests/full_scenario.sh
+ NO_FORMATTING=true ./tooling-e2e-tests/recovery_scenario.sh
+ NO_FORMATTING=true ./tooling-e2e-tests/many_actors.sh
diff --git a/.github/workflows/_ts-checks.yml b/.github/workflows/_ts-checks.yml
new file mode 100644
index 00000000..f9e8a19f
--- /dev/null
+++ b/.github/workflows/_ts-checks.yml
@@ -0,0 +1,69 @@
+---
+name: Run linter and tests for all Typescript modules
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+env:
+ PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: ${{ vars.SHIELDER_CONTRACT_ADDRESS }}
+
+jobs:
+ main:
+ name: Run lints and tests
+ runs-on: [self-hosted, Linux, X64, small]
+ timeout-minutes: 10
+
+ steps:
+ - name: Display variables
+ run: |
+ echo "PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: \
+ ${{ env.PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS }}"
+
+ - uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Cache pnpm modules
+ uses: actions/cache@v4
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-
+
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+
+ - name: Download generated wasm from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: crates-shielder-wasm-pkg
+ path: crates/shielder-wasm/pkg
+
+ - name: Install Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: latest
+
+ - name: Install dependencies (shielder-sdk)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/shielder-sdk
+
+ - name: Build shielder-sdk
+ run: pnpm build
+ working-directory: ts/shielder-sdk
+
+ - name: Run lint checks (shielder-sdk)
+ run: pnpm lint
+ working-directory: ts/shielder-sdk
diff --git a/.github/workflows/_ts-sdk-playwright-tests.yml b/.github/workflows/_ts-sdk-playwright-tests.yml
new file mode 100644
index 00000000..61a5c628
--- /dev/null
+++ b/.github/workflows/_ts-sdk-playwright-tests.yml
@@ -0,0 +1,257 @@
+---
+name: Run sharded Playwright tests for shielder-sdk
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+jobs:
+ build-rust-binary:
+ name: Build Rust binary
+ runs-on: ubuntu-22.04
+ timeout-minutes: 10
+ env:
+ RUSTC_WRAPPER: sccache
+ steps:
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Build Rust binary
+ run: cargo build --manifest-path crates/test-ts-conversions/Cargo.toml
+
+ - name: Build relayer
+ run: cd crates/shielder-relayer && make build
+
+ - name: DOCKER | Build and push latest docker image
+ id: build-image
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ builder: ${{ steps.buildx.outputs.name }}
+ file: ./crates/shielder-relayer/docker/Dockerfile.client
+ tags: shielder-relayer
+ outputs: type=docker,dest=/tmp/shielder-relayer.tar
+
+ - name: Upload binary to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-ts-conversions-binary
+ path: target/debug/test-ts-conversions
+ retention-days: 1
+
+ - name: Upload docker image to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: shielder-relayer-docker-image
+ path: /tmp/shielder-relayer.tar
+ retention-days: 1
+
+ ts-sdk-playwright-tests:
+ name: Run shielder-sdk Playwright tests
+ runs-on: ubuntu-22.04
+ needs: [build-rust-binary]
+ timeout-minutes: 10
+ strategy:
+ fail-fast: false
+ matrix:
+ # When increasing parallelism, make it so at least 2 tests are run per worker
+ # by having `shardTotal <= total_number_of_tests / 2`.
+ # This way repeated usage of WASM wrappers within worker is tested as a side effect.
+ shardIndex: [1]
+ shardTotal: [1]
+ threads: [st, mt]
+ steps:
+ - uses: webfactory/ssh-agent@v0.9.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Cache pnpm modules
+ uses: actions/cache@v4
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-
+
+ - name: Install Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Run anvil node in background
+ shell: bash
+ run: make anvil &
+
+ - name: Install dependencies
+ shell: bash
+ run: make deps
+
+ - name: Download generated contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: generated-contracts
+ path: contracts
+
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+
+ - name: Deploy eth contracts
+ shell: bash
+ run: |
+ NETWORK=anvil make deploy-contracts
+ SHIELDER_CONTRACT_ADDRESS=$(
+ NETWORK=anvil make deploy-contracts \
+ | grep 'Shielder deployed at:' | awk '{print $NF}')
+ echo "SHIELDER_CONTRACT_ADDRESS=${SHIELDER_CONTRACT_ADDRESS}" >> $GITHUB_ENV
+
+ - name: Download generated wasm from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: crates-shielder-wasm-pkg
+ path: crates/shielder-wasm/pkg
+
+ - name: Download binary from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: test-ts-conversions-binary
+ path: target/debug
+
+ - name: Download relayer image from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: shielder-relayer-docker-image
+ path: /tmp
+
+ - name: Load relayer image
+ run: docker load --input /tmp/shielder-relayer.tar
+
+ - name: Run shielder-relayer
+ run: |
+ source ../../tooling-e2e-tests/local_env.sh
+ DOCKER_USER="$(id -u):$(id -g)" \
+ RELAYER_CONTAINER_NAME=shielder-relayer \
+ RELAYER_DOCKER_IMAGE=shielder-relayer \
+ ./run-relayer.sh&
+ working-directory: crates/shielder-relayer
+
+ - name: Executable permissions
+ run: chmod +x target/debug/test-ts-conversions
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: latest
+
+ - name: Install dependencies (shielder-sdk)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/shielder-sdk
+
+ - name: Build shielder-sdk
+ run: pnpm build
+ working-directory: ts/shielder-sdk
+
+ - name: Install dependencies (shielder-sdk-tests)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/shielder-sdk-tests
+
+ - name: Install Playwright dependencies (shielder-sdk-tests)
+ run: pnpm postinstall
+ working-directory: ts/shielder-sdk-tests
+
+ - name: Build shielder-sdk-tests
+ run: pnpm build
+ working-directory: ts/shielder-sdk-tests
+
+ - name: Run tests (shielder-sdk-tests)
+ run: |
+ if [[ ${{ matrix.threads }} == "st" ]]; then
+ CONFIG="playwright.singlethreaded.config.mjs"
+ else
+ CONFIG="playwright.multithreaded.config.mjs"
+ fi
+ source ../../tooling-e2e-tests/local_env.sh
+ RELAYER_SIGNER_ADDRESSES="$RELAYER_SIGNER_ADDRESSES" \
+ pnpm playwright test --config $CONFIG \
+ --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
+ working-directory: ts/shielder-sdk-tests
+
+ - name: Upload blob report to GitHub Actions Artifacts
+ if: ${{ !cancelled() }}
+ uses: actions/upload-artifact@v4
+ with:
+ name: "ts-sdk-tests-shard-report\
+ -${{ matrix.threads }}\
+ -${{ matrix.shardIndex }}\
+ -${{ matrix.shardTotal }}"
+ path: ts/shielder-sdk-tests/blob-report
+ retention-days: 1
+
+ merge-reports:
+ if: ${{ !cancelled() }}
+ needs: [ts-sdk-playwright-tests]
+ strategy:
+ fail-fast: false
+ matrix:
+ threads: [mt]
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 18
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Download blob reports from GitHub Actions Artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: all-blob-reports
+ pattern: ts-sdk-tests-shard-report-${{ matrix.threads }}-*
+ merge-multiple: true
+
+ - name: Print merged report
+ run: npx playwright merge-reports --reporter list ./all-blob-reports
+
+ - name: Store merged report in HTML
+ run: npx playwright merge-reports --reporter html ./all-blob-reports
+
+ - name: Upload HTML report
+ uses: actions/upload-artifact@v4
+ with:
+ name: ts-sdk-tests-report-${{ matrix.threads }}-attempt-${{ github.run_attempt }}
+ path: playwright-report
+ retention-days: 14
+
+ clean-rust-artifact:
+ name: Clean rust artifacts
+ runs-on: ubuntu-22.04
+ if: ${{ always() }}
+ needs: [ts-sdk-playwright-tests]
+ steps:
+ - uses: geekyeggo/delete-artifact@v5
+ with:
+ name: |
+ test-ts-conversions-binary
+ shielder-relayer-docker-image
diff --git a/.github/workflows/manual-browser-extension-deployment.yml b/.github/workflows/manual-browser-extension-deployment.yml
new file mode 100644
index 00000000..d930119b
--- /dev/null
+++ b/.github/workflows/manual-browser-extension-deployment.yml
@@ -0,0 +1,99 @@
+---
+name: "Manual browser extension deployment"
+on:
+ workflow_dispatch:
+ inputs:
+ deployment_type:
+ description: "Deployment type"
+ required: true
+ default: "preview"
+ type: choice
+ options:
+ - "preview"
+ - "prod"
+env:
+ VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
+ VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
+ PROD_OR_PREVIEW: ${{ inputs.deployment_type == 'prod' && '--prod' || '' }}
+ NODE_VERSION: 18
+ PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: ${{ vars.SHIELDER_CONTRACT_ADDRESS }}
+jobs:
+ build-contracts:
+ name: Build contracts
+ uses: ./.github/workflows/_build-contracts.yml
+ secrets: inherit
+ build-wasm-packages:
+ name: Build wasm packages
+ uses: ./.github/workflows/_build-wasm-packages.yml
+ secrets: inherit
+ build-deploy-browser-extension:
+ name: Build and deploy browser extension
+ needs: [build-contracts, build-wasm-packages]
+ runs-on: ubuntu-22.04
+ timeout-minutes: 60
+ steps:
+ - name: Display variables
+ run: |
+ echo "PROD_OR_PREVIEW: ${{ env.PROD_OR_PREVIEW }}"
+ echo "SHIELDER_CONTRACT_ADDRESS: ${{ env.PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS }}"
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Cache pnpm modules
+ uses: actions/cache@v4
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-
+ - name: Download compiled contracts from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: contract-artifacts
+ path: artifacts
+ - name: Download generated wasm from artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: crates-shielder-wasm-pkg
+ path: crates/shielder-wasm/pkg
+ - name: Use Node.js ${{ env.NODE_VERSION }}
+ uses: actions/setup-node@v4.0.2
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4.0.0
+ with:
+ version: latest
+ - name: Install dependencies (shielder-sdk)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/shielder-sdk
+ - name: Build shielder-sdk
+ run: pnpm build
+ working-directory: ts/shielder-sdk
+ - name: Install dependencies (browser-extension)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/browser-extension
+ - name: Build extension (webapp)
+ run: pnpm build
+ working-directory: ts/browser-extension
+ - name: Pull vercel data
+ run: vercel pull --token=${{ secrets.VERCEL_TOKEN }}
+ working-directory: ts/browser-extension
+ - name: Build for vercel
+ run: vercel build ${{ env.PROD_OR_PREVIEW }} --token=${{ secrets.VERCEL_TOKEN }}
+ working-directory: ts/browser-extension
+ - name: Deploy to vercel
+ run: |
+ vercel deploy \
+ --prebuilt ${{ env.PROD_OR_PREVIEW }} \
+ --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt
+ echo "frontend preview deployment:
$(cat deployment-url.txt)" > deployment-url.txt
+ working-directory: ts/browser-extension
+ clean-wasm-artifact:
+ name: Clean wasm artifact
+ if: ${{ always() }}
+ needs: [build-wasm-packages, build-deploy-browser-extension]
+ steps:
+ - uses: geekyeggo/delete-artifact@v5
+ with:
+ name: |
+ crates-shielder-wasm-pkg
diff --git a/.github/workflows/manual-publish-dev-env.yml b/.github/workflows/manual-publish-dev-env.yml
new file mode 100644
index 00000000..6272e25b
--- /dev/null
+++ b/.github/workflows/manual-publish-dev-env.yml
@@ -0,0 +1,125 @@
+---
+name: "Build and deploy development environment"
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build-and-push-relayer:
+ name: Build and push shielder-relayer
+ runs-on: [self-hosted, Linux, X64, medium]
+ steps:
+ - name: GIT | Checkout
+ uses: actions/checkout@v4
+
+ - name: DOCKER | Build and push
+ uses: ./.github/actions/shielder-relayer/build-and-push
+ id: build_shielder_relayer
+ with:
+ aws-mainnet-ecr-access-key-id: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }}
+ aws-mainnet-ecr-access-key: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }}
+ ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }}
+ outputs:
+ image_tag: ${{ steps.build_shielder_relayer.outputs.image_tag }}
+
+ shielder-sdk:
+ name: Build and push shielder-sdk
+ runs-on: [self-hosted, Linux, X64, medium]
+ steps:
+ - name: GIT | Checkout
+ uses: actions/checkout@v4
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Install wasm-pack
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+
+ - name: Install Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18
+
+ - uses: pnpm/action-setup@v4
+ with:
+ version: latest
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Install deps
+ run: make deps
+
+ - name: Compile eth contracts
+ run: make compile-contracts
+
+ - name: Build shielder-wasm
+ run: make all
+ working-directory: crates/shielder-wasm
+
+ - name: Install dependencies (shielder-sdk)
+ run: pnpm install --frozen-lockfile
+ working-directory: ts/shielder-sdk
+
+ - name: Build shielder-sdk
+ run: pnpm build
+ working-directory: ts/shielder-sdk
+
+ - name: Add .npmrc with publish token
+ run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_PUBLISHING_KEY }}" > .npmrc
+ working-directory: ts/shielder-sdk
+
+ - name: Publish shielder-sdk
+ run: pnpm publish --access restricted --no-git-checks
+ working-directory: ts/shielder-sdk
+
+ tooling-dev:
+ name: Generate developer scripts
+ runs-on: [self-hosted, Linux, X64, medium]
+ steps:
+ - name: GIT | Checkout
+ uses: actions/checkout@v4
+
+ - name: Install Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Install deps
+ run: make deps
+
+ - name: Compile eth contracts
+ run: make compile-contracts
+
+ - name: Generate developer scripts
+ run: make generate-tooling-dev
+
+ - name: Upload developer scripts to artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: tooling-dev
+ path: tooling-dev
+ include-hidden-files: true
+ retention-days: 14
diff --git a/.github/workflows/on-pull-request-commit.yml b/.github/workflows/on-pull-request-commit.yml
new file mode 100644
index 00000000..c53f1728
--- /dev/null
+++ b/.github/workflows/on-pull-request-commit.yml
@@ -0,0 +1,68 @@
+---
+name: PR commit
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+concurrency:
+ group: "${{ github.ref }}-${{ github.workflow }}"
+ cancel-in-progress: true
+
+jobs:
+
+ check-vars-and-secrets:
+ name: Check vars and secrets
+ uses: ./.github/workflows/_check-vars-and-secrets.yml
+ secrets: inherit
+
+ build-contracts:
+ name: Generate and compile contracts
+ needs: [check-vars-and-secrets]
+ uses: ./.github/workflows/_build-contracts.yml
+ secrets: inherit
+
+ deploy-contracts:
+ name: Deploy contracts
+ needs: [build-contracts]
+ uses: ./.github/workflows/_deploy-contracts.yml
+ secrets: inherit
+
+ rust-crates-checks:
+ name: Rust crates checks
+ needs: [build-contracts]
+ uses: ./.github/workflows/_rust-crates-checks.yml
+ secrets: inherit
+
+ build-wasm-packages:
+ name: Build wasm packages
+ needs: [check-vars-and-secrets]
+ uses: ./.github/workflows/_build-wasm-packages.yml
+ secrets: inherit
+
+ ts-checks:
+ name: Typescript modules checks
+ needs: [build-contracts, build-wasm-packages]
+ uses: ./.github/workflows/_ts-checks.yml
+ secrets: inherit
+
+ ts-sdk-playwright-tests:
+ name: Typescript shielder-sdk Playwright tests
+ needs: [build-contracts, build-wasm-packages]
+ uses: ./.github/workflows/_ts-sdk-playwright-tests.yml
+ secrets: inherit
+
+ clean-wasm-artifact:
+ name: Clean wasm artifact
+ runs-on: ubuntu-22.04
+ if: ${{ always() }}
+ # dependencies should include all jobs, which interact with wasm artifact
+ needs: [build-wasm-packages, ts-checks, ts-sdk-playwright-tests]
+ steps:
+ - uses: geekyeggo/delete-artifact@v5
+ with:
+ name: |
+ crates-shielder-wasm-pkg
diff --git a/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml b/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml
new file mode 100644
index 00000000..621d8b00
--- /dev/null
+++ b/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml
@@ -0,0 +1,43 @@
+---
+name: "[TESTNET] Build and deploy shielder-relayer"
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build-and-push:
+ name: Build and push shielder-relayer
+ runs-on: [self-hosted, Linux, X64, medium]
+ steps:
+ - name: GIT | Checkout
+ uses: actions/checkout@v4
+
+ - name: DOCKER | Build and push
+ uses: ./.github/actions/shielder-relayer/build-and-push
+ id: build_shielder_relayer
+ with:
+ aws-mainnet-ecr-access-key-id: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }}
+ aws-mainnet-ecr-access-key: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }}
+ ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }}
+ outputs:
+ image_tag: ${{ steps.build_shielder_relayer.outputs.image_tag }}
+
+ deploy:
+ name: Deploy shielder-relayer
+ needs: [build-and-push]
+ runs-on: [self-hosted, Linux, X64, medium]
+ steps:
+ - name: GIT | Checkout
+ uses: actions/checkout@v4
+
+ - name: KUSTOMIZE | Deploy
+ uses: ./.github/actions/shielder-relayer/deploy
+ id: deploy_shielder_relayer
+ with:
+ environment: testnet-dev
+ image-tag: ${{ needs.build-and-push.outputs.image_tag }}
+ autocommit-author: ${{ secrets.AUTOCOMMIT_AUTHOR }}
+ autocommit-email: ${{ secrets.AUTOCOMMIT_EMAIL }}
+ github-token: ${{ secrets.CI_GH_TOKEN }}
+ kustomize-version: ${{ vars.KUSTOMIZE_VERSION }}
+ ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }}
diff --git a/.github/workflows/testnet-nightly-e2e.yml b/.github/workflows/testnet-nightly-e2e.yml
new file mode 100644
index 00000000..3f4e9cec
--- /dev/null
+++ b/.github/workflows/testnet-nightly-e2e.yml
@@ -0,0 +1,119 @@
+---
+name: Nightly E2E tests run on testnet
+
+on:
+ schedule:
+ - cron: '00 23 * * *'
+ workflow_dispatch:
+
+concurrency:
+ group: "${{ github.ref }}-${{ github.workflow }}"
+ cancel-in-progress: true
+
+jobs:
+ circuits-benches:
+ name: Run benches for shielder-circuits crate
+ runs-on: [self-hosted, Linux, X64, large]
+ timeout-minutes: 10
+ env:
+ RUSTC_WRAPPER: sccache
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Run benches for shielder-circuits
+ run: cd crates/shielder-circuits && make bench
+
+ e2e-tests:
+ name: Run E2E tests on testnet
+ runs-on: ubuntu-22.04
+ timeout-minutes: 60
+ env:
+ RUSTC_WRAPPER: sccache
+ CACHE_VERSION: 1
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v4
+
+ - name: Restore rust cache
+ uses: actions/cache@v4
+ with:
+ key: "${{ runner.os }}\
+ -rust\
+ -${{ env.CACHE_VERSION }}\
+ -build\
+ -${{ hashFiles('**/Cargo.toml') }}"
+ path: |
+ ~/.cargo/bin/
+ ~/.cargo/registry/index/
+ ~/.cargo/registry/cache/
+ ~/.cargo/git/db/
+ ~/.cache/sccache/
+ ~/.rustup/
+ target/
+ restore-keys: |
+ ${{ runner.os }}-rust-${{ env.CACHE_VERSION }}-build-
+ ${{ runner.os }}-rust-${{ env.CACHE_VERSION }}
+
+ - name: Prepare Rust env
+ uses: ./.github/actions/prepare-rust-env
+ with:
+ poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+ zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@v1.2.0
+ with:
+ cache-key: custom-seed-coverage-${{ github.ref_name }}
+ cache-restore-keys: |-
+ contract-suite
+ version: nightly-31dd1f77fd9156d09836486d97963cec7f555343
+
+ - name: Node deps
+ run: make deps
+
+ - name: Generate Solidity contracts
+ run: make generate-verifier-contracts
+
+ - name: Compile eth contracts
+ shell: bash
+ run: make compile-contracts
+
+ - name: Run e2e tooling tests
+ env:
+ DEPLOYER_PRIVATE_KEY: ${{ secrets.CI_TESTNET_DEPLOYER_PRIVATE_KEY }}
+ ALICE_PUBLIC_KEY: ${{ vars.CI_TESTNET_ALICE_PUBLIC_KEY }}
+ ALICE_PRIVATE_KEY: ${{ secrets.CI_TESTNET_ALICE_PRIVATE_KEY }}
+ BOB_PUBLIC_KEY: ${{ vars.CI_TESTNET_BOB_PUBLIC_KEY }}
+ BOB_PRIVATE_KEY: ${{ secrets.CI_TESTNET_BOB_PRIVATE_KEY }}
+ CHARLIE_PUBLIC_KEY: ${{ vars.CI_TESTNET_CHARLIE_PUBLIC_KEY }}
+ CHARLIE_PRIVATE_KEY: ${{ secrets.CI_TESTNET_CHARLIE_PRIVATE_KEY }}
+ FEE_DESTINATION: ${{ vars.CI_TESTNET_FEE_DESTINATION }}
+ FEE_DESTINATION_KEY: ${{ secrets.CI_TESTNET_FEE_DESTINATION_KEY }}
+ RELAYER_SIGNER_ADDRESSES: ${{ vars.CI_TESTNET_RELAYER_SIGNER_ADDRESSES }}
+ RELAYER_SIGNING_KEYS: ${{ secrets.CI_TESTNET_RELAYER_SIGNING_KEYS }}
+ run: |
+ NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/full_scenario.sh
+ NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/recovery_scenario.sh
+ NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/many_actors.sh
+
+ slack-notification:
+ name: Slack notification
+ runs-on: ubuntu-22.04
+ needs: [circuits-benches, e2e-tests]
+ if: >
+ !cancelled() &&
+ github.event_name != 'workflow_dispatch'
+ steps:
+ - name: Send Slack message
+ uses: Cardinal-Cryptography/github-actions/slack-notification@v7
+ with:
+ notify-on: "failure"
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_ZKOS }}
diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml
new file mode 100644
index 00000000..576ef08b
--- /dev/null
+++ b/.github/workflows/yaml-lint.yml
@@ -0,0 +1,20 @@
+---
+name: GH Action YAML linter
+
+on:
+ pull_request:
+ paths:
+ - '.github/**.yml'
+ - '.github/**.yaml'
+
+concurrency:
+ group: ${{ github.ref }}-${{ github.workflow }}
+ cancel-in-progress: true
+
+jobs:
+ main:
+ name: YAML Lint
+ runs-on: ubuntu-22.04
+ steps:
+ - name: LINT | Execute YAML linter
+ uses: Cardinal-Cryptography/github-actions/yaml-lint@v7
diff --git a/.github/workflows/yaml-validate.yml b/.github/workflows/yaml-validate.yml
new file mode 100644
index 00000000..9b801b82
--- /dev/null
+++ b/.github/workflows/yaml-validate.yml
@@ -0,0 +1,20 @@
+---
+name: GH Action YAML validator
+
+on:
+ pull_request:
+ paths:
+ - '.github/**.yml'
+ - '.github/**.yaml'
+
+concurrency:
+ group: ${{ github.ref }}-${{ github.workflow }}
+ cancel-in-progress: true
+
+jobs:
+ main:
+ name: YAML Validate
+ runs-on: ubuntu-22.04
+ steps:
+ - name: VALIDATE | Execute github-actions-validator
+ uses: Cardinal-Cryptography/github-actions/yaml-validate@v7.2.0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..80ebb8a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+.idea/
+__pycache__/
+addresses.json
+artifacts/
+broadcast/
+cache/
+node_modules/
+target/
+.DS_Store
+.vscode/
+contracts/*Key.sol
+contracts/*Verifier.sol
+**/*output.log
+
+tooling-dev/*
+!tooling-dev/Makefile
+!tooling-dev/README.md
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 00000000..4cbde364
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,38 @@
+{
+ "overrides": [
+ {
+ "files": "*.sol",
+ "options": {
+ "printWidth": 80,
+ "tabWidth": 4,
+ "useTabs": false,
+ "singleQuote": false,
+ "bracketSpacing": true
+ }
+ },
+ {
+ "files": "*.yml",
+ "options": {}
+ },
+ {
+ "files": "*.yaml",
+ "options": {}
+ },
+ {
+ "files": "*.toml",
+ "options": {}
+ },
+ {
+ "files": "*.json",
+ "options": {}
+ },
+ {
+ "files": "*.js",
+ "options": {}
+ },
+ {
+ "files": "*.ts",
+ "options": {}
+ }
+ ]
+}
diff --git a/.solhint.json b/.solhint.json
new file mode 100644
index 00000000..618f911c
--- /dev/null
+++ b/.solhint.json
@@ -0,0 +1,21 @@
+{
+ "extends": "solhint:recommended",
+ "plugins": ["prettier"],
+ "rules": {
+ "prettier/prettier": "error",
+ "quotes": ["error", "double"],
+ "no-inline-assembly": "",
+ "no-global-import": "error",
+ "no-empty-blocks": "",
+ "reason-string": "error",
+ "func-visibility": [
+ "warn",
+ {
+ "ignoreConstructors": true
+ }
+ ],
+ "avoid-low-level-calls": "",
+ "no-unused-import": "error",
+ "no-unused-vars": "error"
+ }
+}
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 00000000..426afe26
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1 @@
+nodejs 18.19.0
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 00000000..e4970927
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,5913 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
+
+[[package]]
+name = "alloy-chains"
+version = "0.1.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470"
+dependencies = [
+ "alloy-primitives",
+ "num_enum",
+ "strum",
+]
+
+[[package]]
+name = "alloy-consensus"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e"
+dependencies = [
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "auto_impl",
+ "c-kzg",
+ "derive_more",
+ "serde",
+]
+
+[[package]]
+name = "alloy-contract"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "917f7d12cf3971dc8c11c9972f732b35ccb9aaaf5f28f2f87e9e6523bee3a8ad"
+dependencies = [
+ "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",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "alloy-dyn-abi"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cf633ae9a1f0c82fdb9e559ed2be1c8e415c3e48fc47e1feaf32c6078ec0cdd"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-primitives",
+ "alloy-sol-type-parser",
+ "alloy-sol-types",
+ "const-hex",
+ "itoa",
+ "serde",
+ "serde_json",
+ "winnow",
+]
+
+[[package]]
+name = "alloy-eip2930"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "serde",
+]
+
+[[package]]
+name = "alloy-eip7702"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rlp",
+ "k256",
+ "serde",
+]
+
+[[package]]
+name = "alloy-eips"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85"
+dependencies = [
+ "alloy-eip2930",
+ "alloy-eip7702",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "c-kzg",
+ "derive_more",
+ "once_cell",
+ "serde",
+ "sha2",
+]
+
+[[package]]
+name = "alloy-json-abi"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a500037938085feed8a20dbfc8fce58c599db68c948cfae711147175dee392c"
+dependencies = [
+ "alloy-primitives",
+ "alloy-sol-type-parser",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "alloy-json-rpc"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fa8a1a3c4cbd221f2b8e3693aeb328fca79a757fe556ed08e47bbbc2a70db7"
+dependencies = [
+ "alloy-primitives",
+ "alloy-sol-types",
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+ "tracing",
+]
+
+[[package]]
+name = "alloy-network"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-json-rpc",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "alloy-signer",
+ "alloy-sol-types",
+ "async-trait",
+ "auto_impl",
+ "futures-utils-wasm",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "alloy-network-primitives"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-primitives"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3aeeb5825c2fc8c2662167058347cd0cafc3cb15bcb5cdb1758a63c2dca0409e"
+dependencies = [
+ "alloy-rlp",
+ "bytes",
+ "cfg-if",
+ "const-hex",
+ "derive_more",
+ "foldhash",
+ "getrandom",
+ "hashbrown 0.15.2",
+ "hex-literal",
+ "indexmap 2.6.0",
+ "itoa",
+ "k256",
+ "keccak-asm",
+ "paste",
+ "proptest",
+ "rand",
+ "ruint",
+ "rustc-hash",
+ "serde",
+ "sha3 0.10.8",
+ "tiny-keccak",
+]
+
+[[package]]
+name = "alloy-provider"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6"
+dependencies = [
+ "alloy-chains",
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-json-rpc",
+ "alloy-network",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-rpc-client",
+ "alloy-rpc-types-eth",
+ "alloy-transport",
+ "alloy-transport-http",
+ "async-stream",
+ "async-trait",
+ "auto_impl",
+ "dashmap",
+ "futures",
+ "futures-utils-wasm",
+ "lru",
+ "pin-project",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+ "tokio",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "alloy-rlp"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f"
+dependencies = [
+ "alloy-rlp-derive",
+ "arrayvec",
+ "bytes",
+]
+
+[[package]]
+name = "alloy-rlp-derive"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "alloy-rpc-client"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "370143ed581aace6e663342d21d209c6b2e34ee6142f7d6675adb518deeaf0dc"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-primitives",
+ "alloy-transport",
+ "alloy-transport-http",
+ "futures",
+ "pin-project",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tokio-stream",
+ "tower",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "alloy-rpc-types"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ffc534b7919e18f35e3aa1f507b6f3d9d92ec298463a9f6beaac112809d8d06"
+dependencies = [
+ "alloy-primitives",
+ "alloy-rpc-types-engine",
+ "alloy-rpc-types-eth",
+ "alloy-serde",
+ "serde",
+]
+
+[[package]]
+name = "alloy-rpc-types-engine"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0285c4c09f838ab830048b780d7f4a4f460f309aa1194bb049843309524c64c"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "derive_more",
+ "jsonwebtoken",
+ "rand",
+ "serde",
+ "strum",
+]
+
+[[package]]
+name = "alloy-rpc-types-eth"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87"
+dependencies = [
+ "alloy-consensus",
+ "alloy-eips",
+ "alloy-network-primitives",
+ "alloy-primitives",
+ "alloy-rlp",
+ "alloy-serde",
+ "alloy-sol-types",
+ "derive_more",
+ "itertools 0.13.0",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "alloy-serde"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600"
+dependencies = [
+ "alloy-primitives",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "alloy-signer"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fd4e0ad79c81a27ca659be5d176ca12399141659fef2bcbfdc848da478f4504"
+dependencies = [
+ "alloy-primitives",
+ "async-trait",
+ "auto_impl",
+ "elliptic-curve",
+ "k256",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "alloy-signer-local"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494e0a256f3e99f2426f994bcd1be312c02cb8f88260088dacb33a8b8936475f"
+dependencies = [
+ "alloy-consensus",
+ "alloy-network",
+ "alloy-primitives",
+ "alloy-signer",
+ "async-trait",
+ "k256",
+ "rand",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "alloy-sol-macro"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c0279d09463a4695788a3622fd95443625f7be307422deba4b55dd491a9c7a1"
+dependencies = [
+ "alloy-sol-macro-expander",
+ "alloy-sol-macro-input",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "alloy-sol-macro-expander"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4feea540fc8233df2ad1156efd744b2075372f43a8f942a68b3b19c8a00e2c12"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-sol-macro-input",
+ "const-hex",
+ "heck",
+ "indexmap 2.6.0",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+ "syn-solidity",
+ "tiny-keccak",
+]
+
+[[package]]
+name = "alloy-sol-macro-input"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0ad281f3d1b613af814b66977ee698e443d4644a1510962d0241f26e0e53ae"
+dependencies = [
+ "alloy-json-abi",
+ "const-hex",
+ "dunce",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde_json",
+ "syn 2.0.89",
+ "syn-solidity",
+]
+
+[[package]]
+name = "alloy-sol-type-parser"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96eff16c797438add6c37bb335839d015b186c5421ee5626f5559a7bfeb38ef5"
+dependencies = [
+ "serde",
+ "winnow",
+]
+
+[[package]]
+name = "alloy-sol-types"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff34e0682d6665da243a3e81da96f07a2dd50f7e64073e382b1a141f5a2a2f6"
+dependencies = [
+ "alloy-json-abi",
+ "alloy-primitives",
+ "alloy-sol-macro",
+ "const-hex",
+ "serde",
+]
+
+[[package]]
+name = "alloy-transport"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ac3e97dad3d31770db0fc89bd6a63b789fbae78963086733f960cf32c483904"
+dependencies = [
+ "alloy-json-rpc",
+ "base64 0.22.1",
+ "futures-util",
+ "futures-utils-wasm",
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+ "tokio",
+ "tower",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "alloy-transport-http"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212"
+dependencies = [
+ "alloy-json-rpc",
+ "alloy-transport",
+ "reqwest",
+ "serde_json",
+ "tower",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
+
+[[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-asm"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20"
+dependencies = [
+ "num-bigint",
+ "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-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-std"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c"
+dependencies = [
+ "num-traits",
+ "rand",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "askama"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
+dependencies = [
+ "askama_derive",
+ "askama_escape",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
+dependencies = [
+ "askama_parser",
+ "basic-toml",
+ "mime",
+ "mime_guess",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "askama_escape"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
+
+[[package]]
+name = "askama_parser"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "async-channel"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
+dependencies = [
+ "concurrent-queue",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[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.89",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "aurora-engine-modexp"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5"
+dependencies = [
+ "hex",
+ "num",
+]
+
+[[package]]
+name = "auto_impl"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "axum"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "serde_json",
+ "serde_path_to_error",
+ "serde_urlencoded",
+ "sync_wrapper 1.0.2",
+ "tokio",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "rustversion",
+ "sync_wrapper 1.0.2",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets 0.52.6",
+]
+
+[[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 = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
+[[package]]
+name = "basic-toml"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
+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",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "blake2b_simd"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "block-padding",
+ "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-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "blst"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874"
+dependencies = [
+ "cc",
+ "glob",
+ "threadpool",
+ "zeroize",
+]
+
+[[package]]
+name = "bollard"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aed08d3adb6ebe0eff737115056652670ae290f177759aac19c30456135f94c"
+dependencies = [
+ "base64 0.22.1",
+ "bollard-stubs",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "hex",
+ "home",
+ "http",
+ "http-body-util",
+ "hyper",
+ "hyper-named-pipe",
+ "hyper-rustls 0.26.0",
+ "hyper-util",
+ "hyperlocal-next",
+ "log",
+ "pin-project-lite",
+ "rustls 0.22.4",
+ "rustls-native-certs 0.7.3",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_repr",
+ "serde_urlencoded",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-util",
+ "tower-service",
+ "url",
+ "winapi",
+]
+
+[[package]]
+name = "bollard-stubs"
+version = "1.44.0-rc.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709d9aa1c37abb89d40f19f5d0ad6f0d88cb1581264e571c9350fc5bb89cf1c5"
+dependencies = [
+ "serde",
+ "serde_repr",
+ "serde_with",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "byte-slice-cast"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "c-kzg"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928"
+dependencies = [
+ "blst",
+ "cc",
+ "glob",
+ "hex",
+ "libc",
+ "once_cell",
+ "serde",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chacha20"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "chacha20poly1305"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
+dependencies = [
+ "aead",
+ "chacha20",
+ "cipher",
+ "poly1305",
+ "zeroize",
+]
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "serde",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+ "zeroize",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[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 = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "const-hex"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "487981fa1af147182687064d0a2c336586d337a606595ced9ffb0c685c250c73"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "hex",
+ "proptest",
+ "serde",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
+[[package]]
+name = "content-encryption"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chacha20poly1305",
+ "rust-argon2",
+]
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crossterm"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
+dependencies = [
+ "bitflags 1.3.2",
+ "crossterm_winapi",
+ "libc",
+ "mio 0.8.11",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-bigint"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
+
+[[package]]
+name = "der"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+ "serde",
+]
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "derive_more"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[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.89",
+ "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",
+ "subtle",
+]
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "docker_credential"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07"
+dependencies = [
+ "base64 0.21.7",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "downcast"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
+
+[[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.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
+
+[[package]]
+name = "ecdsa"
+version = "0.16.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
+dependencies = [
+ "der",
+ "digest 0.10.7",
+ "elliptic-curve",
+ "rfc6979",
+ "signature",
+ "spki",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "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",
+ "generic-array",
+ "group",
+ "pkcs8",
+ "rand_core",
+ "sec1",
+ "subtle",
+ "zeroize",
+]
+
+[[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-as-inner"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "enumn"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "event-listener"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+dependencies = [
+ "event-listener",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "evm-utils"
+version = "0.1.0"
+dependencies = [
+ "alloy-sol-types",
+ "hex",
+ "revm",
+ "revm-interpreter",
+ "revm-precompile",
+ "revm-primitives",
+ "sha3 0.10.8",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
+
+[[package]]
+name = "fastrlp"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418"
+dependencies = [
+ "arrayvec",
+ "auto_impl",
+ "bytes",
+]
+
+[[package]]
+name = "ff"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
+dependencies = [
+ "bitvec",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "fixed-hash"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534"
+dependencies = [
+ "byteorder",
+ "rand",
+ "rustc-hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fragile"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
+
+[[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-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[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 = "fuzzy-matcher"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
+dependencies = [
+ "thread_local",
+]
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+ "zeroize",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap 2.6.0",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "halo2_poseidon"
+version = "0.2.0"
+source = "git+ssh://git@github.com/Cardinal-Cryptography/poseidon-gadget?branch=poseidon2-pow7#af9a8b342b2d3b1f9074d09840171677dd9077ec"
+dependencies = [
+ "arrayvec",
+ "bitvec",
+ "ff",
+ "group",
+ "halo2_proofs",
+ "halo2curves",
+ "hex",
+ "lazy_static",
+ "rand",
+ "subtle",
+ "uint",
+]
+
+[[package]]
+name = "halo2_proofs"
+version = "0.3.0"
+source = "git+https://github.com/privacy-scaling-explorations/halo2?tag=v0.3.0#73408a140737d8336490452193b21f5a7a94e7de"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "halo2curves",
+ "rand_chacha",
+ "rand_core",
+ "rayon",
+ "serde",
+ "serde_derive",
+ "sha3 0.9.1",
+ "tracing",
+]
+
+[[package]]
+name = "halo2_solidity_verifier"
+version = "0.2.0"
+dependencies = [
+ "alloy-primitives",
+ "alloy-sol-types",
+ "askama",
+ "evm-utils",
+ "halo2_proofs",
+ "itertools 0.13.0",
+ "rand",
+ "ruint",
+ "shielder-circuits",
+ "shielder-rust-sdk",
+]
+
+[[package]]
+name = "halo2curves"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db81d01d0bbfec9f624d7590fc6929ee2537a64ec1e080d8f8c9e2d2da291405"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "lazy_static",
+ "num-bigint",
+ "num-traits",
+ "pairing",
+ "pasta_curves",
+ "paste",
+ "rand",
+ "rand_core",
+ "rayon",
+ "static_assertions",
+ "subtle",
+]
+
+[[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.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+ "serde",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "hex-literal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
+
+[[package]]
+name = "hickory-proto"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512"
+dependencies = [
+ "async-trait",
+ "cfg-if",
+ "data-encoding",
+ "enum-as-inner",
+ "futures-channel",
+ "futures-io",
+ "futures-util",
+ "idna 0.4.0",
+ "ipnet",
+ "once_cell",
+ "rand",
+ "thiserror 1.0.69",
+ "tinyvec",
+ "tokio",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "hickory-resolver"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "hickory-proto",
+ "ipconfig",
+ "lru-cache",
+ "once_cell",
+ "parking_lot",
+ "rand",
+ "resolv-conf",
+ "smallvec",
+ "thiserror 1.0.69",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "hostname"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
+dependencies = [
+ "libc",
+ "match_cfg",
+ "winapi",
+]
+
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "human_bytes"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91f255a4535024abf7640cb288260811fc14794f62b063652ed349f9a6c2348e"
+
+[[package]]
+name = "hyper"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-named-pipe"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278"
+dependencies = [
+ "hex",
+ "hyper",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
+ "winapi",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "log",
+ "rustls 0.22.4",
+ "rustls-native-certs 0.7.3",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls 0.25.0",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls 0.23.19",
+ "rustls-native-certs 0.8.1",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls 0.26.0",
+ "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",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "hyperlocal-next"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc"
+dependencies = [
+ "hex",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+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-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.89",
+]
+
+[[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.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.2",
+ "serde",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "inquire"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a"
+dependencies = [
+ "bitflags 2.6.0",
+ "crossterm",
+ "dyn-clone",
+ "fuzzy-matcher",
+ "fxhash",
+ "newline-converter",
+ "once_cell",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "integration-tests"
+version = "0.1.0"
+dependencies = [
+ "alloy-contract",
+ "alloy-primitives",
+ "alloy-sol-types",
+ "evm-utils",
+ "halo2_proofs",
+ "halo2_solidity_verifier",
+ "hex",
+ "rand",
+ "rstest",
+ "serde",
+ "serde_json",
+ "shielder-circuits",
+ "shielder-rust-sdk",
+]
+
+[[package]]
+name = "ipconfig"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
+dependencies = [
+ "socket2",
+ "widestring",
+ "windows-sys 0.48.0",
+ "winreg",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "jsonwebtoken"
+version = "9.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f"
+dependencies = [
+ "base64 0.21.7",
+ "js-sys",
+ "pem",
+ "ring",
+ "serde",
+ "serde_json",
+ "simple_asn1",
+]
+
+[[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",
+]
+
+[[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 = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.166"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36"
+
+[[package]]
+name = "libm"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "lru"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
+dependencies = [
+ "hashbrown 0.15.2",
+]
+
+[[package]]
+name = "lru-cache"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
+dependencies = [
+ "linked-hash-map",
+]
+
+[[package]]
+name = "match_cfg"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
+[[package]]
+name = "matchit"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "metrics"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884adb57038347dfbaf2d5065887b6cf4312330dc8e94bc30a1a839bd79d3261"
+dependencies = [
+ "ahash",
+ "portable-atomic",
+]
+
+[[package]]
+name = "metrics-exporter-prometheus"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6"
+dependencies = [
+ "base64 0.22.1",
+ "indexmap 2.6.0",
+ "metrics",
+ "metrics-util",
+ "quanta",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "metrics-util"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4259040465c955f9f2f1a4a8a16dc46726169bca0f88e8fb2dbeced487c3e828"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "metrics",
+ "num_cpus",
+ "quanta",
+ "sketches-ddsketch",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "mockall"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2"
+dependencies = [
+ "cfg-if",
+ "downcast",
+ "fragile",
+ "mockall_derive",
+ "predicates",
+ "predicates-tree",
+]
+
+[[package]]
+name = "mockall_derive"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898"
+dependencies = [
+ "cfg-if",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework 2.11.1",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "newline-converter"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
+dependencies = [
+ "num-bigint",
+ "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",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-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.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "object"
+version = "0.36.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "openssl"
+version = "0.10.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-src"
+version = "300.4.1+3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
+dependencies = [
+ "cc",
+ "libc",
+ "openssl-src",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "pairing"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
+dependencies = [
+ "group",
+]
+
+[[package]]
+name = "parity-scale-codec"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590"
+dependencies = [
+ "arrayvec",
+ "bitvec",
+ "byte-slice-cast",
+ "impl-trait-for-tuples",
+ "parity-scale-codec-derive",
+ "rustversion",
+ "serde",
+]
+
+[[package]]
+name = "parity-scale-codec-derive"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "parse-display"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a"
+dependencies = [
+ "parse-display-derive",
+ "regex",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "parse-display-derive"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "regex",
+ "regex-syntax 0.8.5",
+ "structmeta",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "pasta_curves"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "lazy_static",
+ "rand",
+ "static_assertions",
+ "subtle",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pem"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
+dependencies = [
+ "base64 0.22.1",
+ "serde",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pest"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
+dependencies = [
+ "memchr",
+ "thiserror 1.0.69",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "poly1305"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
+dependencies = [
+ "cpufeatures",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "predicates"
+version = "3.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
+dependencies = [
+ "anstyle",
+ "predicates-core",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
+dependencies = [
+ "predicates-core",
+ "termtree",
+]
+
+[[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.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
+[[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.89",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "proptest"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d"
+dependencies = [
+ "bit-set",
+ "bit-vec",
+ "bitflags 2.6.0",
+ "lazy_static",
+ "num-traits",
+ "rand",
+ "rand_chacha",
+ "rand_xorshift",
+ "regex-syntax 0.8.5",
+ "rusty-fork",
+ "tempfile",
+ "unarray",
+]
+
+[[package]]
+name = "quanta"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
+dependencies = [
+ "crossbeam-utils",
+ "libc",
+ "once_cell",
+ "raw-cpuid",
+ "wasi",
+ "web-sys",
+ "winapi",
+]
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
+dependencies = [
+ "bytes",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls 0.23.19",
+ "socket2",
+ "thiserror 2.0.3",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
+dependencies = [
+ "bytes",
+ "getrandom",
+ "rand",
+ "ring",
+ "rustc-hash",
+ "rustls 0.23.19",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.3",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "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",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "raw-cpuid"
+version = "11.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+ "wasm_sync",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "wasm_sync",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.4.9",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "relative-path"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+
+[[package]]
+name = "reqwest"
+version = "0.12.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "hickory-resolver",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls 0.27.3",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls 0.23.19",
+ "rustls-native-certs 0.8.1",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper 1.0.2",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tokio-rustls 0.26.0",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "webpki-roots",
+ "windows-registry",
+]
+
+[[package]]
+name = "resolv-conf"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
+dependencies = [
+ "hostname",
+ "quick-error",
+]
+
+[[package]]
+name = "revm"
+version = "14.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f"
+dependencies = [
+ "auto_impl",
+ "cfg-if",
+ "dyn-clone",
+ "revm-interpreter",
+ "revm-precompile",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "revm-interpreter"
+version = "10.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2"
+dependencies = [
+ "revm-primitives",
+ "serde",
+]
+
+[[package]]
+name = "revm-precompile"
+version = "11.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b"
+dependencies = [
+ "aurora-engine-modexp",
+ "c-kzg",
+ "cfg-if",
+ "k256",
+ "once_cell",
+ "revm-primitives",
+ "ripemd",
+ "secp256k1",
+ "sha2",
+ "substrate-bn",
+]
+
+[[package]]
+name = "revm-primitives"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101"
+dependencies = [
+ "alloy-eip2930",
+ "alloy-eip7702",
+ "alloy-primitives",
+ "auto_impl",
+ "bitflags 2.6.0",
+ "bitvec",
+ "cfg-if",
+ "dyn-clone",
+ "enumn",
+ "hex",
+ "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 = "ring"
+version = "0.17.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ripemd"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "rlp"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec"
+dependencies = [
+ "bytes",
+ "rustc-hex",
+]
+
+[[package]]
+name = "rstest"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "rstest_macros",
+ "rustc_version 0.4.1",
+]
+
+[[package]]
+name = "rstest_macros"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a"
+dependencies = [
+ "cfg-if",
+ "glob",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "relative-path",
+ "rustc_version 0.4.1",
+ "syn 2.0.89",
+ "unicode-ident",
+]
+
+[[package]]
+name = "ruint"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286"
+dependencies = [
+ "alloy-rlp",
+ "ark-ff 0.3.0",
+ "ark-ff 0.4.2",
+ "bytes",
+ "fastrlp",
+ "num-bigint",
+ "num-traits",
+ "parity-scale-codec",
+ "primitive-types",
+ "proptest",
+ "rand",
+ "rlp",
+ "ruint-macro",
+ "serde",
+ "valuable",
+ "zeroize",
+]
+
+[[package]]
+name = "ruint-macro"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18"
+
+[[package]]
+name = "rust-argon2"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d9848531d60c9cbbcf9d166c885316c24bc0e2a9d3eba0956bb6cbbd79bc6e8"
+dependencies = [
+ "base64 0.21.7",
+ "blake2b_simd",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustc-hash"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+dependencies = [
+ "rand",
+]
+
+[[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.23",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
+dependencies = [
+ "bitflags 2.6.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
+dependencies = [
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
+dependencies = [
+ "openssl-probe",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework 2.11.1",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework 3.0.1",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+dependencies = [
+ "web-time",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
+dependencies = [
+ "fnv",
+ "quick-error",
+ "tempfile",
+ "wait-timeout",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[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.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
+dependencies = [
+ "rand",
+ "secp256k1-sys",
+]
+
+[[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.6.0",
+ "core-foundation 0.9.4",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8"
+dependencies = [
+ "bitflags 2.6.0",
+ "core-foundation 0.10.0",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[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.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.133"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
+dependencies = [
+ "indexmap 2.6.0",
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
+name = "serde_repr"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817"
+dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.6.0",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha3"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "keccak",
+ "opaque-debug",
+]
+
+[[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 = "shellexpand"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
+dependencies = [
+ "dirs",
+]
+
+[[package]]
+name = "shielder-circuits"
+version = "0.1.0"
+source = "git+ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits?branch=main#744505c7e4fbb615c6db46500e6d2a3b02253a6a"
+dependencies = [
+ "console_error_panic_hook",
+ "halo2_poseidon",
+ "halo2_proofs",
+ "human_bytes",
+ "once_cell",
+ "rand",
+ "rand_chacha",
+ "rand_core",
+ "rayon",
+ "sha2",
+ "static_assertions",
+ "strum",
+ "strum_macros",
+ "thiserror 1.0.69",
+ "transcript",
+]
+
+[[package]]
+name = "shielder-cli"
+version = "0.1.0"
+dependencies = [
+ "alloy-contract",
+ "alloy-eips",
+ "alloy-network",
+ "alloy-primitives",
+ "alloy-provider",
+ "alloy-rpc-types-eth",
+ "alloy-signer-local",
+ "alloy-sol-types",
+ "anyhow",
+ "clap",
+ "content-encryption",
+ "inquire",
+ "rand",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "shellexpand",
+ "shielder-circuits",
+ "shielder-relayer",
+ "shielder-rust-sdk",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "shielder-relayer"
+version = "0.1.0"
+dependencies = [
+ "alloy-provider",
+ "alloy-rpc-types",
+ "alloy-signer",
+ "alloy-signer-local",
+ "anyhow",
+ "async-channel",
+ "axum",
+ "clap",
+ "metrics",
+ "metrics-exporter-prometheus",
+ "openssl",
+ "rand",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "shielder-rust-sdk",
+ "testcontainers",
+ "tokio",
+ "tower-http",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "shielder-rust-sdk"
+version = "0.1.0"
+dependencies = [
+ "alloy-contract",
+ "alloy-network",
+ "alloy-primitives",
+ "alloy-provider",
+ "alloy-rpc-types",
+ "alloy-signer-local",
+ "alloy-sol-types",
+ "alloy-transport",
+ "anyhow",
+ "byteorder",
+ "halo2_proofs",
+ "halo2curves",
+ "hex",
+ "lazy_static",
+ "log",
+ "mockall",
+ "num-bigint",
+ "rand",
+ "secp256k1",
+ "serde",
+ "sha3 0.10.8",
+ "shielder-circuits",
+ "static_assertions",
+ "thiserror 1.0.69",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "shielder-wasm"
+version = "0.1.0"
+dependencies = [
+ "console_error_panic_hook",
+ "getrandom",
+ "halo2_poseidon",
+ "halo2_proofs",
+ "rand",
+ "rand_chacha",
+ "rand_core",
+ "rayon",
+ "sha2",
+ "shielder-circuits",
+ "shielder-rust-sdk",
+ "wasm-bindgen",
+ "wasm-bindgen-rayon",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio 0.8.11",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest 0.10.7",
+ "rand_core",
+]
+
+[[package]]
+name = "simple_asn1"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "thiserror 1.0.69",
+ "time",
+]
+
+[[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.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "socket2"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "stress-testing"
+version = "0.1.0"
+dependencies = [
+ "alloy-provider",
+ "alloy-rpc-types",
+ "alloy-signer-local",
+ "anyhow",
+ "clap",
+ "rand",
+ "reqwest",
+ "shielder-circuits",
+ "shielder-relayer",
+ "shielder-rust-sdk",
+ "tokio",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "structmeta"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "structmeta-derive",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "structmeta-derive"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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.89",
+]
+
+[[package]]
+name = "substrate-bn"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "lazy_static",
+ "rand",
+ "rustc-hex",
+]
+
+[[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.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn-solidity"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdaa7b9e815582ba343a20c66627437cf45f1c6fba7f69772cbfd1358c7e197"
+dependencies = [
+ "paste",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags 2.6.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 = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "tempfile"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "termtree"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+
+[[package]]
+name = "test-ts-conversions"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "halo2_proofs",
+ "shielder-circuits",
+ "shielder-rust-sdk",
+]
+
+[[package]]
+name = "testcontainers"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81abdf87437235a275fd0fecaa6ca2c6af28240506e695e9abe84597b3431b35"
+dependencies = [
+ "async-trait",
+ "bollard",
+ "bollard-stubs",
+ "bytes",
+ "dirs",
+ "docker_credential",
+ "either",
+ "futures",
+ "log",
+ "memchr",
+ "parse-display",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "url",
+]
+
+[[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.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
+dependencies = [
+ "thiserror-impl 2.0.3",
+]
+
+[[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.89",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "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.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "time-macros"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.41.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio 1.0.2",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[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.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
+dependencies = [
+ "rustls 0.22.4",
+ "rustls-pki-types",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls 0.23.19",
+ "rustls-pki-types",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap 2.6.0",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper 0.1.2",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697"
+dependencies = [
+ "bitflags 2.6.0",
+ "bytes",
+ "http",
+ "pin-project-lite",
+ "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.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+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-serde"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
+]
+
+[[package]]
+name = "transcript"
+version = "0.2.0"
+source = "git+ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits?branch=main#744505c7e4fbb615c6db46500e6d2a3b02253a6a"
+dependencies = [
+ "halo2_proofs",
+ "itertools 0.13.0",
+ "ruint",
+ "sha3 0.10.8",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "universal-hash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
+dependencies = [
+ "crypto-common",
+ "subtle",
+]
+
+[[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 1.0.3",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[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 = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-rayon"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e02b7785fe15de188657b7d3a234ef042bfd8da10822016915e06d4e29cba7"
+dependencies = [
+ "crossbeam-channel",
+ "js-sys",
+ "rayon",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "wasm_sync"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff360cade7fec41ff0e9d2cda57fe58258c5f16def0e21302394659e6bbb0ea"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.26.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "widestring"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
+
+[[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.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+dependencies = [
+ "windows-result",
+ "windows-strings",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.89",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..a9ea81f2
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,94 @@
+[workspace]
+resolver = "2"
+
+members = ["crates/*"]
+
+[workspace.package]
+edition = "2021"
+authors = ["Cardinal"]
+homepage = "https://alephzero.org"
+license = "Apache-2.0"
+categories = ["cryptography"]
+repository = "https://github.com/Cardinal-Cryptography/zkOS"
+
+[workspace.dependencies]
+alloy-contract = { version = "0.4.2" }
+alloy-eips = { version = "0.4.2" }
+alloy-network = { version = "0.4.2" }
+alloy-primitives = { version = "0.8.5" }
+alloy-provider = { version = "0.4.2" }
+alloy-rpc-types = { version = "0.4.2" }
+alloy-rpc-types-eth = { version = "0.4.2" }
+alloy-signer = { version = "0.4.2" }
+alloy-signer-local = { version = "0.4.2" }
+alloy-sol-types = { version = "0.8.5" }
+alloy-transport = { version = "0.4.2" }
+anyhow = { version = "1.0.86", default-features = false }
+askama = { version = "0.12.0", default-features = false }
+async-channel = { version = "2.3.1" }
+axum = { version = "0.7.7" }
+byteorder = { version = "1.4.3" }
+chacha20poly1305 = { version = "0.10.1", default-features = false }
+clap = { version = "4.5.8" }
+console_error_panic_hook = { version = "0.1.7" }
+criterion = { version = "0.5.1" }
+darling = { version = "0.20.10" }
+getrandom = { version = "0.2" }
+halo2_poseidon = { git = "ssh://git@github.com/Cardinal-Cryptography/poseidon-gadget", branch = "poseidon2-pow7" }
+halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v0.3.0", default-features = false }
+halo2curves = { version = "0.6.0", default-features = false }
+hex = { version = "0.4.3" }
+human_bytes = { version = "0.4.3", default-features = false }
+inquire = { version = "0.7.5" }
+itertools = { version = "0.13.0" }
+js-sys = { version = "0.3.61" }
+lazy_static = { version = "1.5.0" }
+log = { version = "0.4.22" }
+metrics = { version = "0.23.0", default-features = false }
+metrics-exporter-prometheus = { version = "0.15.3", default-features = false }
+mockall = { version = "0.13.0" }
+num-bigint = { version = "0.4.3" }
+once_cell = { version = "1.20.2" }
+paste = { version = "1.0.15" }
+proc-macro2 = { version = "1.0.86" }
+quote = { version = "1.0.37" }
+rand = { version = "0.8.5" }
+rand_chacha = { version = "0.3.1" }
+rand_core = { version = "0.6.4" }
+rayon = { version = "1.8" }
+reqwest = { version = "0.12.5" }
+revm = { version = "14.0.3", default-features = false }
+revm-interpreter = { version = "10.0.3", default-features = false }
+revm-precompile = { version = "11.0.3", default-features = false }
+revm-primitives = { version = "10.0.0", default-features = false }
+rstest = "0.23.0"
+ruint = { version = "1" }
+rust-argon2 = { version = "2.1.0" }
+secp256k1 = { version = "0.29.1" }
+serde = { version = "1.0.203" }
+serde_json = { version = "1.0.120" }
+sha2 = { version = "0.10.8" }
+sha3 = { version = "0.10" }
+shellexpand = { version = "3.1.0" }
+shielder-circuits = { git = "ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits", branch = "main" }
+#shielder-circuits = { path = "/home/filip/CloudStation/aleph/zkOS-circuits/crates/shielder-circuits" }
+static_assertions = { version = "1.1.0" }
+strum = { version = "0.26.3" }
+strum_macros = { version = "0.26.3" }
+syn = { version = "2.0.79" }
+testcontainers = { version = "0.19.0" }
+thiserror = { version = "1.0.61" }
+tokio = { version = "1.38.0" }
+tower-http = { version = "0.6.1" }
+tracing = { version = "0.1.40" }
+tracing-subscriber = { version = "0.3.18" }
+wasm-bindgen = { version = "0.2.92" }
+wasm-bindgen-rayon = { version = "1.2.1" }
+wasm-bindgen-test = { version = "0.3.42" }
+
+# Local dependencies
+content-encryption = { path = "crates/content-encryption", default-features = false }
+evm-utils = { path = "crates/evm-utils" }
+halo2_solidity_verifier = { path = "crates/halo2-verifier" }
+shielder-relayer = { path = "crates/shielder-relayer" }
+shielder-rust-sdk = { path = "crates/shielder-rust-sdk" }
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..9ea1b432
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,90 @@
+NETWORK ?= anvil
+PRIVATE_KEY ?= 0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 # pkey of the dev account `0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E` prefunded with ETH on all networks
+
+.PHONY: help
+help: # Show help for each of the Makefile recipes.
+ @grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | sort | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done
+
+.PHONY: clean
+clean: # Remove all generated data
+clean:
+ git clean -fdX
+
+.PHONY: deps
+deps: # Install dependencies
+deps:
+ npm install
+
+.PHONY: anvil
+anvil: # Run local anvil node
+anvil:
+ ./scripts/aleph-anvil.sh -p 8545
+
+.PHONY: stop-anvil
+stop-anvil: # Stop local anvil node
+stop-anvil:
+ pkill anvil
+
+.PHONY: watch-contracts
+watch-contracts: # watcher on the eth contracts. Scripts dir is watched by default
+watch-contracts:
+ forge build --watch contracts/*.sol --watch scripts/*.sol
+
+.PHONY: format-contracts
+format-contracts: # Format solidity contracts
+format-contracts:
+ npx prettier --write --plugin=prettier-plugin-solidity 'contracts/*.sol' 'scripts/*.sol'
+
+.PHONY: lint-contracts
+lint-contracts: # Lint solidity contracts
+lint-contracts:
+ npx solhint -c .solhint.json 'contracts/*.sol' 'scripts/*.sol'
+
+.PHONY: compile-contracts
+compile-contracts: # Compile solidity contracts
+compile-contracts: generate-verifier-contracts
+ forge build
+
+.PHONY: deploy-contracts
+deploy-contracts: # Deploy solidity contracts
+deploy-contracts:
+ifeq ($(NETWORK),anvil)
+ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 forge script DeployShielderScript --broadcast --rpc-url anvil
+else
+ PRIVATE_KEY=$(PRIVATE_KEY) forge script DeployShielderScript --broadcast --rpc-url $(NETWORK)
+endif
+
+.PHONY: generate-poseidon-contracts
+generate-poseidon-contracts: # Generate Poseidon contract
+generate-poseidon-contracts:
+ python3 poseidon2-solidity/generate_t8.py > contracts/Poseidon2T8Assembly.sol
+ npx prettier --write --plugin=prettier-plugin-solidity 'contracts/Poseidon2T*Assembly.sol'
+
+.PHONY: generate-verifier-contracts
+generate-verifier-contracts: # Generate relation verifier contracts
+generate-verifier-contracts:
+ cd crates/halo2-verifier
+ cargo run --release --bin halo2_solidity_verifier_generator
+ $(MAKE) format-contracts
+
+.PHONY: format-rust
+format-rust: # Format all rust crates
+format-rust:
+ cargo +nightly fmt --all -- --check
+
+.PHONY: lint-rust
+lint-rust: # Lint all rust crates
+lint-rust:
+ cargo clippy --release -- -D warnings
+
+.PHONY: generate-tooling-dev
+generate-tooling-dev: # Generate tooling-dev package
+generate-tooling-dev:
+ cp tooling-e2e-tests/local_env.sh tooling-dev/
+ cp crates/shielder-relayer/run-relayer.sh tooling-dev/
+ cp package.json tooling-dev/
+ cp package-lock.json tooling-dev/
+ cp foundry.toml tooling-dev/
+ cp -r contracts tooling-dev/
+ cp -r scripts tooling-dev/
+ git rev-parse --short=7 HEAD > tooling-dev/.git-sha
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..a1510d2e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,90 @@
+[![LOGO][logo]][aleph-homepage]
+
+[![Test suite][tests-badge]][tests]
+[![Nightly Testnet E2E tests][nightly-tests-badge]][nightly-tests]
+
+# Shielder: A First Iteration of zkOS
+
+Welcome to Shielder, the first iteration of zkOS by Aleph Zero.
+Shielder is designed to provide a seamless integration of zero-knowledge (ZK) privacy into Ethereum Virtual Machine (EVM) compatible environments with subsecond proving times.
+
+## Table of Contents
+
+- [Introduction](#introduction)
+- [Features](#features)
+- [Architecture](#architecture)
+- [Getting Started](#getting-started)
+ - [Prerequisites](#prerequisites)
+ - [Usage](#usage)
+- [License](#license)
+
+## Introduction
+
+Shielder is part of the Aleph Zero zkOS initiative, aimed at delivering Privacy-as-a-Service for Web3. With zkOS, developers can integrate ZK-based privacy into their applications without deep cryptographic knowledge.
+
+## Features
+
+- **EVM Compatibility**: Easily integrate with existing Ethereum-based applications.
+- **Subsecond Proving**: Achieve zero-knowledge proofs in 600-800 ms on standard hardware.
+- **High Performance**: Supports up to 250ms block time and processes thousands of transactions per second.
+- **Developer-Friendly**: Comprehensive tooling and frameworks to simplify integration.
+- **Privacy-Enhanced**: Build and deploy privacy-enhanced applications effortlessly.
+
+# Architecture
+
+Shielder is built utilizing the following components:
+
+- **Aleph Zero WASM L1**: Serves as the Data Availability layer.
+- **EVM Layer 2 Rollup**: Leverages Arbitrum Anytrust DAC technology for fast and secure execution.
+- **Developer Tooling**: Includes Gelato’s web3 services, account abstraction, functions, VRF, oracles, block explorers, indexers, and multisig support.
+
+## Getting Started
+
+### Prerequisites
+
+Before you begin, ensure you have the following:
+
+- Node.js and npm installed
+- Docker (optional, for containerized deployment)
+- An Ethereum wallet
+
+### Usage
+
+Clone the repository and install the dependencies:
+
+```bash
+git clone git@github.com:Cardinal-Cryptography/zkOS.git
+cd zkOS
+make deps
+```
+
+Boot a local node:
+
+```bash
+make anvil
+```
+
+Compile & deploy the smart contract suite:
+
+```bash
+make deploy-contracts
+```
+
+### Deploying to anvil
+
+The command below will use `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` as a deployer:
+
+```bash
+NETWORK=anvil make deploy-contracts
+```
+
+## License
+
+Shielder is licensed under the MIT License. See the LICENSE file for more details.
+
+[aleph-homepage]: https://alephzero.org
+[logo]: logo.png
+[tests]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/on-master-branch-push-pull_request.yml
+[tests-badge]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/on-master-branch-push-pull_request.yml/badge.svg
+[nightly-tests]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/nightly-testnet-e2e.yml
+[nightly-tests-badge]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/nightly-testnet-e2e.yml/badge.svg
diff --git a/contracts/ArbSysMock.sol b/contracts/ArbSysMock.sol
new file mode 100644
index 00000000..4785bb4a
--- /dev/null
+++ b/contracts/ArbSysMock.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.26;
+
+import { IArbSys } from "./IArbSys.sol";
+
+/**
+ * Mock implementation of ArbSys for testing purposes.
+ * @dev Returns just the `block.number`. Will work well when run on L1 chain.
+ */
+contract ArbSysMock is IArbSys {
+ /**
+ * @notice Get Arbitrum block number
+ * @return block number as uint256
+ */
+ function arbBlockNumber() external view override returns (uint256) {
+ return block.number;
+ }
+}
diff --git a/contracts/IArbSys.sol b/contracts/IArbSys.sol
new file mode 100644
index 00000000..fb94c591
--- /dev/null
+++ b/contracts/IArbSys.sol
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.14;
+
+// Interface taken from https://docs.arbitrum.io/build-decentralized-apps/precompiles/reference#arbsys.
+
+/**
+ * @title System level functionality
+ * @notice For use by contracts to interact with core L2-specific functionality.
+ * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.
+ */
+interface IArbSys {
+ /**
+ * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
+ * @return block number as uint256
+ */
+ function arbBlockNumber() external view returns (uint256);
+}
diff --git a/contracts/MerkleTree.sol b/contracts/MerkleTree.sol
new file mode 100644
index 00000000..a8dd6200
--- /dev/null
+++ b/contracts/MerkleTree.sol
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity 0.8.26;
+import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
+import { Poseidon2T8Assembly as Poseidon2 } from "./Poseidon2T8Assembly.sol";
+
+/*
+ * Merkle Tree with Poseidon2
+ */
+
+library MerkleTree {
+ uint256 public constant ARITY = 7;
+ uint256 public constant TREE_HEIGHT = 13;
+ // tree height is computed as ceil(log_{ARITY}(2^36))
+
+ struct MerkleTreeData {
+ mapping(uint256 => uint256) notes;
+ uint256 root;
+ uint256 nextFreeLeafId;
+ uint256 maxLeafId;
+ uint256 firstLeafId;
+ }
+
+ error InvalidTreeHeight();
+ error MaxTreeSizeExceeded();
+ error LeafNotExisting();
+
+ /*
+ * Initialize the tree.
+ */
+ function init(MerkleTreeData storage merkleTree) internal {
+ (merkleTree.maxLeafId, merkleTree.nextFreeLeafId) = treeBounds(
+ TREE_HEIGHT
+ );
+ merkleTree.firstLeafId = merkleTree.nextFreeLeafId;
+ }
+
+ /*
+ * Add a note to the tree.
+ * Returns the index of the note in the tree starting from 0.
+ * If the tree is full, it will revert.
+ */
+ function addNote(
+ MerkleTreeData storage self,
+ uint256 note
+ ) internal returns (uint256) {
+ if (self.nextFreeLeafId > self.maxLeafId) revert MaxTreeSizeExceeded();
+
+ uint256 index = self.nextFreeLeafId;
+ uint256 parent = 0;
+ uint256[ARITY] memory subtrees;
+ self.notes[index] = note;
+
+ for (uint256 i = 0; i < TREE_HEIGHT; ) {
+ unchecked {
+ parent = (index + ARITY - 2) / ARITY;
+ }
+ for (uint256 j = 0; j < ARITY; ) {
+ subtrees[j] = self.notes[parent * ARITY + j - (ARITY - 2)];
+ unchecked {
+ j++;
+ }
+ }
+ note = Poseidon2.hash(subtrees);
+ self.notes[parent] = note;
+
+ index = parent;
+ unchecked {
+ i++;
+ }
+ }
+ self.root = note;
+ self.nextFreeLeafId += 1;
+
+ return self.nextFreeLeafId - self.firstLeafId - 1;
+ }
+
+ /*
+ * Given an index of a leaf return the path from a leaf index to the root.
+ * Leaves are indexed from 0.
+ * Path is an array of length TREE_HEIGHT*ARITY+1, where the first TREE_HEIGHT*ARITY elements are the siblings of the path,
+ * and the last element is the root.
+ * If tree looks like this:
+ * l_3 = hash(l_1, l_2)
+ * l_5 = hash(l_3, l_4)
+ * ...
+ * root = hash(l_71, l_72)
+ * Then the path for l_1 is:
+ * | l_1 l_2 | l_3 l_4 | l_5 l_6 | ... | l_71 l_72 | root |
+ */
+ function getMerklePath(
+ MerkleTreeData storage self,
+ uint256 index
+ ) internal view returns (uint256[] memory) {
+ if (index >= self.nextFreeLeafId - self.firstLeafId) {
+ revert LeafNotExisting();
+ }
+ index += self.firstLeafId;
+
+ uint256[] memory path = new uint256[](TREE_HEIGHT * ARITY + 1);
+
+ uint256 parent = 0;
+ for (uint256 i = 0; i < TREE_HEIGHT; ) {
+ unchecked {
+ parent = (index + ARITY - 2) / ARITY;
+ }
+ for (uint256 j = 0; j < ARITY; ) {
+ path[i * ARITY + j] = self.notes[
+ parent * ARITY + j - (ARITY - 2)
+ ];
+ unchecked {
+ j++;
+ }
+ }
+
+ index = parent;
+ unchecked {
+ i++;
+ }
+ }
+ path[TREE_HEIGHT * ARITY] = self.root;
+
+ return path;
+ }
+
+ /*
+ * Given a tree height, return the maximum index of a leaf and the index of the first leaf.
+ * Throw an error if height is too big.
+ */
+ function treeBounds(
+ uint256 treeHeight
+ ) private pure returns (uint256, uint256) {
+ uint256 size = 1;
+ uint256 power = 1;
+ bool flag = true;
+ for (uint256 i = 1; i <= treeHeight; i++) {
+ (flag, power) = Math.tryMul(power, ARITY);
+ if (!flag) revert InvalidTreeHeight();
+ (flag, size) = Math.tryAdd(size, power);
+ if (!flag) revert InvalidTreeHeight();
+ }
+ return (size, size - power + 1);
+ }
+}
diff --git a/contracts/Permit2.sol b/contracts/Permit2.sol
new file mode 100644
index 00000000..ed2e1140
--- /dev/null
+++ b/contracts/Permit2.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.14;
+
+/* @dev: needed to compile Permit2 */
+/* solhint-disable no-unused-import */
+import { Permit2 } from "@uniswap/permit2/src/Permit2.sol";
diff --git a/contracts/Poseidon2T8Assembly.sol b/contracts/Poseidon2T8Assembly.sol
new file mode 100644
index 00000000..e647f133
--- /dev/null
+++ b/contracts/Poseidon2T8Assembly.sol
@@ -0,0 +1,6682 @@
+pragma solidity 0.8.26;
+library Poseidon2T8Assembly {
+ function hash(uint256[7] memory) public pure returns (uint256) {
+ assembly {
+ function sum() {
+ mstore(
+ 0x140,
+ addmod(
+ add(
+ addmod(
+ add(
+ mload(0x00),
+ add(
+ mload(0x20),
+ add(
+ mload(0x80),
+ add(mload(0xa0), mload(0xc0))
+ )
+ )
+ ),
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x100)
+ ),
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ function mm4(a, b, c, d) {
+ let t0 := add(mload(a), mload(b)) // a + b
+ let t1 := add(mload(c), mload(d)) // + c + d
+ let t2 := add(mload(b), add(mload(b), t1)) // + 2b + c + d
+ let t3 := add(mload(d), add(mload(d), t0)) // a + b + 2d
+ let t4 := add(t1, t1) // 2c + 2d
+ t4 := addmod(
+ t4,
+ t4,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ) // 4c + 4d
+ t4 := addmod(
+ t4,
+ t3,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ) // a + b + 4c + 6d
+ let t5 := add(t0, t0) // 2a + 2b
+ t5 := addmod(
+ t5,
+ t5,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ) // 4a + 4b
+ t5 := addmod(
+ t5,
+ t2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ) // 4a + 6b + c + d
+
+ mstore(
+ a,
+ addmod(
+ t3,
+ t5,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(b, t5)
+ mstore(
+ c,
+ addmod(
+ t2,
+ t4,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(d, t4)
+ }
+
+ function fr_mm() {
+ mm4(0x00, 0x20, 0x80, 0xa0)
+ mm4(0xc0, 0xe0, 0x100, 0x120)
+
+ mstore(0x140, add(mload(0x00), mload(0xc0)))
+ mstore(0x160, add(mload(0x20), mload(0xe0)))
+ mstore(0x180, add(mload(0x80), mload(0x100)))
+ mstore(0x1a0, add(mload(0xa0), mload(0x120)))
+
+ mstore(
+ 0x00,
+ addmod(
+ mload(0x00),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mload(0x20),
+ mload(0x160),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mload(0x80),
+ mload(0x180),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mload(0xa0),
+ mload(0x1a0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mload(0xc0),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mload(0xe0),
+ mload(0x160),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mload(0x100),
+ mload(0x180),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mload(0x120),
+ mload(0x1a0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ function fr_intro(c0, c1, c2, c3, c4, c5, c6, c7) {
+ let state0 := add(mload(0x00), c0)
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state1 := add(mload(0x20), c1)
+ {
+ let var2 := mulmod(
+ state1,
+ state1,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x20,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state1,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state2 := add(mload(0x80), c2)
+ {
+ let var2 := mulmod(
+ state2,
+ state2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x80,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state3 := add(mload(0xa0), c3)
+ {
+ let var2 := mulmod(
+ state3,
+ state3,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0xa0,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state3,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state4 := add(mload(0xc0), c4)
+ {
+ let var2 := mulmod(
+ state4,
+ state4,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0xc0,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state4,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state5 := add(mload(0xe0), c5)
+ {
+ let var2 := mulmod(
+ state5,
+ state5,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0xe0,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state5,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state6 := add(mload(0x100), c6)
+ {
+ let var2 := mulmod(
+ state6,
+ state6,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x100,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state6,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ let state7 := add(mload(0x120), c7)
+ {
+ let var2 := mulmod(
+ state7,
+ state7,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x120,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state7,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+ }
+
+ mstore(0x00, mload(0x080))
+ mstore(0x20, mload(0x0a0))
+ mstore(0x80, mload(0x0c0))
+ mstore(0xa0, mload(0x0e0))
+ mstore(0xc0, mload(0x100))
+ mstore(0xe0, mload(0x120))
+ mstore(0x100, mload(0x140))
+ mstore(0x120, 129127208515966861312)
+
+ fr_mm()
+
+ {
+ fr_intro(
+ 4374910847496570502851666885419112453902517339857936546642776148093208834076,
+ 4043213966675802222711951833799747398544826675171104649923510397774605701432,
+ 10295457532979908351689870330273304172034280885513669796993861960192447770433,
+ 13185549805193951237530306688380766158835192431473268775288108542040064983071,
+ 13031669968593716420209817549905011043748303215734206479455307665118481917735,
+ 18343454766307691225698897877005276380323314575088714109848555232962927806451,
+ 4285598628460968749045653380268362330101985063701482288209687847531702020142,
+ 6396360754966367114418673553740502687780213591488826781874722869496104602554
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 16200804545643582389651312275787196022923363607710794506797044233734656121044,
+ 5134113862164183256837156309894643041635561742417093535155792168400431031128,
+ 16471262385794041608522265868619559042749216664461639171092582570120233458738,
+ 15723793949959091386062587647943267657651324687857644398097267442086421222837,
+ 4446608623965585589069696696206788262733768624291356886053262391248913164030,
+ 12263662121776110063124264291823110630103516514597816100285412992928428141693,
+ 13727309801509560416443333055765002796184618911221393457056781958666764100492,
+ 12035506540047119988708392579833344597280695956718584325712108831864228117468
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 2137349817265832389630431403020686625284455384467896815597687377494641047396,
+ 4748593344659988252042998947010556624672186775256478994223811901919391329801,
+ 3877706675344496756243474607993753102537735202197057886890771729592494656346,
+ 15647915819346078484784806320063471126994550702265590557961181419988789965763,
+ 14405905899560914295870617237758358277304043621193837463463843094804092059239,
+ 14784694522234549653759635058994355941926443631841664622096500140484558680685,
+ 18899741568972126096340573504141014616014744452536151726719977363015788770512,
+ 5451313876118173933795880888264229902146494327637141336196058929430726660258
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 8523490007889545992873929078045575160693040385939070075958015007341678815377,
+ 17290246629648536472352733006841342309105450862473341949043067707842479341967,
+ 14700591146031062723163899911366439421207304211867736420137668775953124921184,
+ 19913634027676989763433084135421222826701272045849433405013103499081618365783,
+ 3259437893706969557036945674914639947393447161093753975815625697652910191444,
+ 16969164682773159039689327973436447588570424605015123874750285193369165651709,
+ 14824538783460991003207046836693352460422165588686218795092602237388721955441,
+ 12294108935004528953312621254245550647064707709668192842054169419944743387026
+ )
+ fr_mm()
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 17887213884740404694263669711691166469270926080573489933611199178426226025621
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 8384861720264271278572752935970765586580871388412738840337100629527015944091
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 11415188990977796463133969050582766732114945674183269184380896042912135094257
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 4043439830090880176534002167931353039116821897062471893640429781805068860710
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 3285981043091489096090035052889181959379926235192733497560048442282261344163
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 5089720679132371154943614112997133982140084176544464385571738300063187139498
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 18113881451258125168676724071576339869643904892995107435540258593798179700430
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 17035511805914875958405421138030015099427303400596998407886140379590312329958
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 3390797776612057923683522652529910602151366267475587231965343130960981907120
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 15950158835044687249587788527739740324819281225343680355516183812452457910587
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 13095279455455100007770712355994786378159656575937178414750768529430123074327
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 15072002081519380677842256312524244159989959621223774105455889608327077539930
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 5023362554662599501385121542720837333112880828506514763527520994117003013587
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 6319655669922293228547410028634618999888313728892929946601369734256669569212
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 18607917525751184282734424082901458732437701986685218970961235088620428347046
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 19286195190293133769283845732974176141991008935236887811137271481948236719579
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 2434370996884752904104098216922445401569159963469965008995898759656475875110
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 4137483869981861013775448278496529445656281590765517233881272272161047390551
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 5435597430877857909644660105310763099627063893382747901672520731247676814123
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 524518289161264304724373110130550500066215933535943135707891179726282748707
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 1751307723466358110098512070987508093607034543894162777595610481901356964264
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 14379457882544169338616440442319667355116934801723810641671825534922887126311
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 17523955073338443114823309995884983834639327123805850756462598717896064390697
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 20763445568370636302460408007645878400428156279959803011940918483997397145304
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 13892617801935783037491120867832099138633690632189685079093341530264003967791
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 1308414123599469965295155060753088653871456878869193033439510811601963545749
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 1662344861162290450810513261934733006057888097213770953767445658429321134478
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 20443177566820274604835505442424845806635697148027328945828753803047179429262
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 8427529718777821395091100109834811066359753665738975680235391126556845526890
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 10946983102263150274549536602153963823993597140192081784834807923027311583069
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 11157903074510728276165582821675613398204544967484723112588784070444164004252
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 14860244753384889920468588445646388769146670323947418785445337100112682476522
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 19667868664387897300981027052569110463992131826750586078083601936180553195445
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 19175638817684058935402017206319086854147207384592219390853570535784533321715
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 12494124141064432118122881935513148491604628118093270612690216186298252805026
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 8278699417806537071403341410219479038256244092883863337094398027472670690868
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 2049673770720342823071350600438028976114490525766655725520666205884117018879
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 15664554456052547545787639212885638054675210894003347948969306359411603741221
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 1180146134238569222341211963576419371564143833462002527404875987379102531306
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 2962366915552448693827078643390229926763401155127973562286181096651222534835
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 8454923055048274473300779886765291623967448890293628249815383532926367395856
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 20839238372362818955853198843590566148294159785089189666161332617686692110358
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 10429808287581498273991832576203872273646856353727095296202247871323130624874
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 9271901703504676095351804139915745802637379886790829560586697548201671614811
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 1277029192330597958592137670619290866893426769940867461830690181234653133789
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 17446271275185238973758317012506224116792211004689801754888372823248750758368
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 18195286995463105065381208020617915527608642263449807357339205385570253103581
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ let state0 := add(
+ mload(0x00),
+ 7174788758503182348118464918825059734075283649341444832906374342273234112306
+ )
+ {
+ let var2 := mulmod(
+ state0,
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ let var4 := mulmod(
+ var2,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ mstore(
+ 0x00,
+ mulmod(
+ mulmod(
+ var4,
+ var2,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ state0,
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ sum()
+ mstore(
+ 0x00,
+ addmod(
+ mulmod(
+ 2600766909924179814780409961696866414079699656430070499803459729017893381997,
+ mload(0x00),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x20,
+ addmod(
+ mulmod(
+ 19293363242678774625215171492393209093707286181479006293654394057747218353607,
+ mload(0x20),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x80,
+ addmod(
+ mulmod(
+ 21414786808156610356356451480905960406647514095406216853368573063004475600640,
+ mload(0x80),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xa0,
+ addmod(
+ mulmod(
+ 8215135898581116354906741804378477022438799156627805573019887031189487620936,
+ mload(0xa0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xc0,
+ addmod(
+ mulmod(
+ 9165814748476180913577766403125055556952884368727238651703828504915350029819,
+ mload(0xc0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0xe0,
+ addmod(
+ mulmod(
+ 15078459252378813527385228808553999657222567675360137586804698725603240352055,
+ mload(0xe0),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x100,
+ addmod(
+ mulmod(
+ 5648186893216350474836221186116590993767413676065426352255299742021094533501,
+ mload(0x100),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ mstore(
+ 0x120,
+ addmod(
+ mulmod(
+ 20725344080263893594397636575905698660034655258256134536883719628954264697683,
+ mload(0x120),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ ),
+ mload(0x140),
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617
+ )
+ )
+ }
+
+ {
+ fr_intro(
+ 8796514263363206892523807527453045861447267504409085409181921818383118315916,
+ 16768762997463189144254377645616439451261123095417712027764595809271347822641,
+ 16981453060376976490300105534864189219102809745136900886818257290108560398681,
+ 13244378809965474246226965753718500997233021263849978441109990117743824114889,
+ 12740391142133165804674923445797846244959706391592825821984559861316164389390,
+ 6357870290401284659894321747392037524252693108822317466922375220086393591413,
+ 21170287578042370349558117969904573035349234404506160746997342913069492593441,
+ 16525914224980087240063471205423966448365920546617852056768902032147570692448
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 15634019475192385983841856902246166130231567044915330197057281032777100628014,
+ 15211113699235347007597795430087519165406233589182463643807945479646234230239,
+ 11632581981084267773704718139511950475422868778548965666580599195374884611609,
+ 5276885296738315848831727579776141799814909987182736480697101231837085016550,
+ 434949722786700336429895586902875655186339324315727400607943925242711893438,
+ 12979202789373856152843455289592254071606068472247565795377585881336039887928,
+ 5516847749540333045414273732117447717673992365056361083316880459671727096711,
+ 20518987206418619025272040970398156181339077686390712133906274083302454217706
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 9534878978823325430033643568356022467018975030745926930968329297399586828153,
+ 16476336232468000195625524343206740870941066529037515612519719879009161459061,
+ 1926056599060283648268377210224971158820380187985593537994203039766892742929,
+ 17089075957295284782165638921108879712741772532192826429152480059028756451044,
+ 3223089692674530160797178366569103602558857774752325464962636799294976059188,
+ 6416339074787194839206567142761438585611573130765891828761271859398335998072,
+ 1336837711227185395110000610845274685426861968384488898787321065604521760869,
+ 3489074920180283241053863308816434113592398030282124098259821386991274215953
+ )
+ fr_mm()
+ }
+
+ {
+ fr_intro(
+ 8077777888803021630069511342690123744058410620326306901310934661394084426536,
+ 12303022515875343188934513158193425297350490121987769437868677898104970156809,
+ 16936067755695119249209357865872131540532280773479227169325938024705653997393,
+ 14737417545438720305707136711758797913375528370944760259267579780726364876676,
+ 6161415340932228722932305870854623786821068005781192281048254066342286470096,
+ 5461556731070720193517122421990625944342168372023166428399391809256130788407,
+ 19769259359420661267913500180453633636582761819177923247133831646093396706859,
+ 15388495767943380117723410224640307626534051664851259898259719796404454480030
+ )
+ fr_mm()
+ }
+ return(0x00, 0x20)
+ }
+ }
+}
diff --git a/contracts/Shielder.sol b/contracts/Shielder.sol
new file mode 100644
index 00000000..e4d4941c
--- /dev/null
+++ b/contracts/Shielder.sol
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity 0.8.26;
+
+import { IArbSys } from "./IArbSys.sol";
+import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import { MerkleTree } from "./MerkleTree.sol";
+import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
+import { UIntSet } from "./UIntSet.sol";
+import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
+
+interface IVerifier {
+ function verifyProof(
+ address vk,
+ bytes calldata proof,
+ uint256[] calldata instances
+ ) external returns (bool);
+}
+
+/// @title Shielder
+/// @author CardinalCryptography
+contract Shielder is
+ Initializable,
+ UUPSUpgradeable,
+ OwnableUpgradeable,
+ PausableUpgradeable
+{
+ using UIntSet for UIntSet.Set;
+ using MerkleTree for MerkleTree.MerkleTreeData;
+
+ // -- Storage --
+
+ /// The contract version, in the form `0x{v1}{v2}{v3}`, where:
+ /// - `v1` is the version of the note schema,
+ /// - `v1.v2` is the version of the circuits used,
+ /// - `v1.v2.v3` is the version of the contract itself.
+ bytes3 public constant CONTRACT_VERSION = 0x000001;
+
+ /// This amount of gas should be sufficient for ether transfers
+ /// and simple fallback function execution, yet still protecting against reentrancy attack.
+ uint256 public constant GAS_LIMIT = 3500;
+
+ /// The range check in circuits will work only if we ensure bounded transaction values
+ /// on the contract side.
+ uint256 public constant MAX_TRANSACTION_AMOUNT = 2 ** 112 - 1;
+
+ /// Safeguards against a scenario when multiple deposits create a shielded account balance
+ /// that fails the new account balance range check in the withdrawal circuit, thus
+ /// making withdrawals impossible. In the contract we can't control a single shielded balance,
+ /// so we control the sum of balances instead.
+ uint256 public constant MAX_CONTRACT_BALANCE = MAX_TRANSACTION_AMOUNT;
+
+ /// The temporary limit for the maximal deposit amount in the MVP version.
+ uint256 public depositLimit;
+
+ /// The address of the Arbitrum system precompile.
+ address private constant ARB_SYS_ADDRESS =
+ 0x0000000000000000000000000000000000000064;
+ IArbSys private arbSysPrecompile;
+
+ // verifier contracts
+ address public newAccountVerifier;
+ address public depositVerifier;
+ address public withdrawVerifier;
+
+ // verification key contracts
+ address public newAccountVerifyingKey;
+ address public depositVerifyingKey;
+ address public withdrawVerifyingKey;
+
+ MerkleTree.MerkleTreeData public merkleTree;
+
+ UIntSet.Set private merkleRoots;
+ // Mapping from nullifier hash to the block at which it was revealed. Actually, the value will be the block number + 1,
+ // so that the default value 0 can be used to indicate that the nullifier has not been revealed.
+ mapping(uint256 => uint256) public nullifiers;
+
+ // -- Events --
+ event NewAccountNative(
+ uint256 idHash,
+ uint256 amount,
+ uint256 newNote,
+ uint256 newNoteIndex
+ );
+ event DepositNative(
+ uint256 idHiding,
+ uint256 amount,
+ uint256 newNote,
+ uint256 newNoteIndex
+ );
+ event WithdrawNative(
+ uint256 idHiding,
+ uint256 amount,
+ address to,
+ uint256 newNote,
+ uint256 newNoteIndex,
+ address relayerAddress,
+ uint256 fee
+ );
+
+ // -- Errors --
+
+ error DepositVerificationFailed();
+ error DuplicatedNullifier();
+ error FeeHigherThanAmount();
+ error MerkleRootDoesNotExist();
+ error NativeTransferFailed();
+ error WithdrawVerificationFailed();
+ error NewAccountVerificationFailed();
+ error ZeroAmount();
+ error AmountOverDepositLimit();
+ error AmountTooHigh();
+ error ContractBalanceLimitReached();
+ error LeafIsNotInTheTree();
+ error PrecompileCallFailed();
+
+ modifier withinDepositLimit() {
+ if (msg.value > depositLimit) revert AmountOverDepositLimit();
+ _;
+ }
+
+ constructor() {
+ _disableInitializers();
+ }
+
+ /// @dev disable possibility to renounce ownership
+ function renounceOwnership() public virtual override onlyOwner {}
+
+ function initialize(
+ address initialOwner,
+ address _newAccountVerifier,
+ address _depositVerifier,
+ address _withdrawVerifier,
+ address _newAccountVerifyingKey,
+ address _depositVerifyingKey,
+ address _withdrawVerifyingKey,
+ uint256 _depositLimit
+ ) public initializer {
+ __Ownable_init(initialOwner);
+ __Pausable_init();
+ _pause();
+
+ merkleTree.init();
+
+ arbSysPrecompile = IArbSys(ARB_SYS_ADDRESS);
+
+ newAccountVerifier = _newAccountVerifier;
+ depositVerifier = _depositVerifier;
+ withdrawVerifier = _withdrawVerifier;
+
+ newAccountVerifyingKey = _newAccountVerifyingKey;
+ depositVerifyingKey = _depositVerifyingKey;
+ withdrawVerifyingKey = _withdrawVerifyingKey;
+
+ depositLimit = _depositLimit;
+ }
+
+ /// @dev required by the OZ UUPS module
+ function _authorizeUpgrade(address) internal override onlyOwner {}
+
+ function pause() external onlyOwner {
+ _pause();
+ }
+
+ function unpause() external onlyOwner {
+ _unpause();
+ }
+
+ /*
+ * Creates a fresh note, with an optional native token deposit.
+ *
+ * This transaction serves as the entrypoint to the Shielder.
+ */
+ function newAccountNative(
+ uint256 newNote,
+ uint256 idHash,
+ bytes calldata proof
+ ) external payable whenNotPaused withinDepositLimit {
+ uint256 amount = msg.value;
+ if (nullifiers[idHash] != 0) revert DuplicatedNullifier();
+ // `address(this).balance` already includes `msg.value`.
+ if (address(this).balance > MAX_CONTRACT_BALANCE)
+ revert ContractBalanceLimitReached();
+
+ // @dev must follow the same order as in the circuit
+ uint256[] memory publicInputs = new uint256[](3);
+ publicInputs[0] = newNote;
+ publicInputs[1] = idHash;
+ publicInputs[2] = amount;
+
+ IVerifier _verifier = IVerifier(newAccountVerifier);
+ bool success = _verifier.verifyProof(
+ newAccountVerifyingKey,
+ proof,
+ publicInputs
+ );
+
+ if (!success) revert NewAccountVerificationFailed();
+
+ uint256 index = merkleTree.addNote(newNote);
+ merkleRoots.add(merkleTree.root);
+ registerNullifier(idHash);
+
+ emit NewAccountNative(idHash, amount, newNote, index);
+ }
+
+ /*
+ * Make a native token deposit into the Shielder
+ */
+ function depositNative(
+ uint256 idHiding,
+ uint256 oldNullifierHash,
+ uint256 newNote,
+ uint256 merkleRoot,
+ bytes calldata proof
+ ) external payable whenNotPaused withinDepositLimit {
+ uint256 amount = msg.value;
+ if (amount == 0) revert ZeroAmount();
+ if (nullifiers[oldNullifierHash] != 0) revert DuplicatedNullifier();
+ if (!merkleRoots.contains(merkleRoot)) revert MerkleRootDoesNotExist();
+ // `address(this).balance` already includes `msg.value`.
+ if (address(this).balance > MAX_CONTRACT_BALANCE)
+ revert ContractBalanceLimitReached();
+
+ // @dev needs to match the order in the circuit
+ uint256[] memory publicInputs = new uint256[](5);
+ publicInputs[0] = idHiding;
+ publicInputs[1] = merkleRoot;
+ publicInputs[2] = oldNullifierHash;
+ publicInputs[3] = newNote;
+ publicInputs[4] = amount;
+
+ IVerifier _verifier = IVerifier(depositVerifier);
+ bool success = _verifier.verifyProof(
+ depositVerifyingKey,
+ proof,
+ publicInputs
+ );
+
+ if (!success) revert DepositVerificationFailed();
+
+ uint256 index = merkleTree.addNote(newNote);
+ merkleRoots.add(merkleTree.root);
+ registerNullifier(oldNullifierHash);
+
+ emit DepositNative(idHiding, msg.value, newNote, index);
+ }
+
+ /*
+ * Withdraw shielded native funds
+ */
+ function withdrawNative(
+ uint256 idHiding,
+ uint256 amount,
+ address withdrawAddress,
+ uint256 merkleRoot,
+ uint256 oldNullifierHash,
+ uint256 newNote,
+ bytes calldata proof,
+ address relayerAddress,
+ uint256 relayerFee
+ ) external whenNotPaused {
+ if (amount == 0) revert ZeroAmount();
+ if (amount <= relayerFee) revert FeeHigherThanAmount();
+ if (amount > MAX_TRANSACTION_AMOUNT) revert AmountTooHigh();
+
+ if (!merkleRoots.contains(merkleRoot)) revert MerkleRootDoesNotExist();
+ if (nullifiers[oldNullifierHash] != 0) revert DuplicatedNullifier();
+
+ // @dev needs to match the order in the circuit
+ uint256[] memory publicInputs = new uint256[](6);
+ publicInputs[0] = idHiding;
+ publicInputs[1] = merkleRoot;
+ publicInputs[2] = oldNullifierHash;
+ publicInputs[3] = newNote;
+ publicInputs[4] = amount;
+
+ bytes memory commitment = abi.encodePacked(
+ CONTRACT_VERSION,
+ addressToUInt256(withdrawAddress),
+ addressToUInt256(relayerAddress),
+ relayerFee
+ );
+ // @dev shifting right by 4 bits so the commitment is smaller from r
+ publicInputs[5] = uint256(keccak256(commitment)) >> 4;
+
+ IVerifier _verifier = IVerifier(withdrawVerifier);
+ bool success = _verifier.verifyProof(
+ withdrawVerifyingKey,
+ proof,
+ publicInputs
+ );
+
+ if (!success) revert WithdrawVerificationFailed();
+
+ uint256 newNoteIndex = merkleTree.addNote(newNote);
+ merkleRoots.add(merkleTree.root);
+ registerNullifier(oldNullifierHash);
+
+ // return the tokens
+ (bool nativeTransferSuccess, ) = withdrawAddress.call{
+ value: amount - relayerFee,
+ gas: GAS_LIMIT
+ }("");
+ if (!nativeTransferSuccess) revert NativeTransferFailed();
+
+ // pay out the fee
+ (nativeTransferSuccess, ) = relayerAddress.call{
+ value: relayerFee,
+ gas: GAS_LIMIT
+ }("");
+ if (!nativeTransferSuccess) revert NativeTransferFailed();
+
+ emit WithdrawNative(
+ idHiding,
+ amount,
+ withdrawAddress,
+ newNote,
+ newNoteIndex,
+ relayerAddress,
+ relayerFee
+ );
+ }
+
+ function registerNullifier(uint256 nullifier) private {
+ uint256 blockNumber = arbSysPrecompile.arbBlockNumber();
+ nullifiers[nullifier] = blockNumber + 1;
+ }
+
+ function addressToUInt256(address addr) public pure returns (uint256) {
+ return uint256(uint160(addr));
+ }
+
+ // --- Getters ---
+
+ /*
+ * Given an index of a leaf return the path from a leaf index to the root,
+ * omitting the root and leaf for gas efficiency,
+ * as they can be derived from hashing their children.
+ */
+
+ function getMerklePath(
+ uint256 id
+ ) external view returns (uint256[] memory) {
+ return merkleTree.getMerklePath(id);
+ }
+
+ // -- Setters ---
+
+ /*
+ * Set the deposit limit for the maximal amount
+ */
+ function setDepositLimit(uint256 _depositLimit) external onlyOwner {
+ depositLimit = _depositLimit;
+ }
+}
diff --git a/contracts/Token.sol b/contracts/Token.sol
new file mode 100644
index 00000000..17386621
--- /dev/null
+++ b/contracts/Token.sol
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity 0.8.26;
+
+import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+
+contract Token is ERC20 {
+ constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
+ _mint(msg.sender, initialSupply);
+ }
+}
diff --git a/contracts/UIntSet.sol b/contracts/UIntSet.sol
new file mode 100644
index 00000000..87702ef5
--- /dev/null
+++ b/contracts/UIntSet.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.26;
+
+library UIntSet {
+ struct Set {
+ mapping(uint256 => bool) exists;
+ }
+
+ function add(Set storage set, uint256 value) internal returns (bool) {
+ if (!set.exists[value]) {
+ set.exists[value] = true;
+ return true;
+ }
+ return false;
+ }
+
+ function contains(
+ Set storage set,
+ uint256 value
+ ) internal view returns (bool) {
+ return set.exists[value];
+ }
+}
diff --git a/crates/content-encryption/Cargo.toml b/crates/content-encryption/Cargo.toml
new file mode 100644
index 00000000..916112a6
--- /dev/null
+++ b/crates/content-encryption/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "content-encryption"
+version = "0.1.0"
+edition.workspace = true
+authors.workspace = true
+homepage.workspace = true
+license.workspace = true
+categories.workspace = true
+repository.workspace = true
+description = "Small library for encrypting and decrypting content with a password."
+
+[lib]
+path = "lib.rs"
+name = "content_encryption"
+
+[dependencies]
+anyhow = { workspace = true }
+chacha20poly1305 = { workspace = true, features = ["alloc"] }
+rust-argon2 = { workspace = true }
+
+[features]
+default = ["std"]
+std = []
diff --git a/crates/content-encryption/lib.rs b/crates/content-encryption/lib.rs
new file mode 100644
index 00000000..bcaaba2c
--- /dev/null
+++ b/crates/content-encryption/lib.rs
@@ -0,0 +1,42 @@
+//! Small library for encrypting and decrypting content with a password.
+
+#![deny(missing_docs)]
+#![cfg_attr(not(feature = "std"), no_std)]
+
+extern crate alloc;
+
+use alloc::vec::Vec;
+
+use anyhow::{anyhow, Result};
+use chacha20poly1305::{aead::Aead, KeyInit, XChaCha20Poly1305};
+
+const SALT: [u8; 32] = [41u8; 32];
+const NONCE: [u8; 24] = [41u8; 24];
+
+fn scheme_from_password(password: &[u8]) -> Result {
+ let key = argon2::hash_raw(password, &SALT, &Default::default())
+ .map_err(|e| anyhow!("Failed to derive key from password: {e}"))?;
+ Ok(XChaCha20Poly1305::new(key.as_slice().into()))
+}
+
+/// Encrypt `content` with `password`.
+pub fn encrypt(content: &[u8], password: &[u8]) -> Result> {
+ scheme_from_password(password)?
+ .encrypt(NONCE.as_slice().into(), content)
+ .map_err(|e| anyhow!("Failed to encrypt data: {e}"))
+}
+
+/// Decrypt `content` with `password`.
+pub fn decrypt(content: &[u8], password: &[u8]) -> Result> {
+ scheme_from_password(password)?
+ .decrypt(NONCE.as_slice().into(), content)
+ .map_err(|e| anyhow!("Failed to decrypt data - probably the password is incorrect: {e}"))
+}
+
+/// Decrypt `content` with `password` and try converting it to `String` right away.
+#[cfg(feature = "std")]
+pub fn decrypt_to_string(content: &[u8], password: &[u8]) -> Result {
+ let decrypted = decrypt(content, password)?;
+ String::from_utf8(decrypted)
+ .map_err(|e| anyhow!("Failed to decrypt data - probably the password is incorrect: {e}"))
+}
diff --git a/crates/evm-utils/Cargo.toml b/crates/evm-utils/Cargo.toml
new file mode 100644
index 00000000..ba28fb11
--- /dev/null
+++ b/crates/evm-utils/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "evm-utils"
+version = "0.1.0"
+edition.workspace = true
+authors.workspace = true
+homepage.workspace = true
+license.workspace = true
+categories.workspace = true
+repository.workspace = true
+
+[dependencies]
+alloy-sol-types = { workspace = true }
+hex = { workspace = true }
+revm = { workspace = true, default-features = false, features = ["std"] }
+revm-interpreter = { workspace = true }
+revm-precompile = { workspace = true }
+revm-primitives = { workspace = true }
+sha3 = { workspace = true }
+thiserror = { workspace = true }
diff --git a/crates/evm-utils/src/compilation.rs b/crates/evm-utils/src/compilation.rs
new file mode 100644
index 00000000..9ade81f6
--- /dev/null
+++ b/crates/evm-utils/src/compilation.rs
@@ -0,0 +1,93 @@
+use std::{
+ io,
+ io::Write,
+ process::{Command, Stdio},
+};
+
+use crate::repo_root_dir;
+
+/// Composition of `compile_solidity` and `find_binary` functions.
+pub fn source_to_bytecode(
+ solidity_code: impl AsRef<[u8]>,
+ contract_name: &str,
+ decode: bool,
+) -> Vec {
+ let compilation_output = compile_solidity(solidity_code);
+ find_binary(&compilation_output, contract_name, decode).unwrap()
+}
+
+/// Given solc compilation output returns the bytecode.
+///
+/// If `decode` is true, the function will attempt to hex-decode the bytecode. Otherwise,
+/// the bytecode is returned as a hex string (as bytes).
+pub fn find_binary(input: &str, contract_name: &str, decode: bool) -> Option> {
+ let search_str = format!("======= :{contract_name} =======\nBinary:\n");
+
+ // Find the position of the search string in the input
+ let start = input.find(&search_str)?;
+
+ // Find the end of the hex blob.
+ let end = input[start + search_str.len()..]
+ .find('\n')
+ .map(|pos| pos + start + search_str.len())?;
+
+ // Extract the relevant part of the input that may contain the binary
+ let binary_section = &input[start + search_str.len()..end].trim();
+
+ if decode {
+ hex::decode(binary_section).ok()
+ } else {
+ Some(binary_section.as_bytes().to_vec())
+ }
+}
+
+/// Compile solidity with `--via-ir` flag, then return creation bytecode.
+///
+/// # Panics
+///
+/// Panics if executable `solc` can not be found, or compilation fails.
+pub fn compile_solidity(solidity: impl AsRef<[u8]>) -> String {
+ let root_dir = repo_root_dir();
+
+ let mut process = match Command::new("solc")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .arg("--bin")
+ .arg("--via-ir")
+ .arg("--optimize")
+ .arg("--base-path")
+ .arg(&root_dir)
+ .arg("--include-path")
+ .arg(root_dir.join("node_modules"))
+ .arg("--include-path")
+ .arg(root_dir.join("contracts"))
+ .arg("-")
+ .spawn()
+ {
+ Ok(process) => process,
+ Err(err) if err.kind() == io::ErrorKind::NotFound => {
+ panic!("Command 'solc' not found");
+ }
+ Err(err) => {
+ panic!("Failed to spawn process with command 'solc':\n{err}");
+ }
+ };
+ process
+ .stdin
+ .take()
+ .unwrap()
+ .write_all(solidity.as_ref())
+ .unwrap();
+ let output = process.wait_with_output().unwrap();
+
+ let stderr = output.stderr;
+ if !stderr.is_empty() {
+ let error = String::from_utf8(stderr).unwrap();
+ if error.contains("Error") {
+ panic!("Compilation error: {error}");
+ }
+ }
+
+ String::from_utf8(output.stdout).unwrap()
+}
diff --git a/crates/evm-utils/src/evm_runner.rs b/crates/evm-utils/src/evm_runner.rs
new file mode 100644
index 00000000..64271e03
--- /dev/null
+++ b/crates/evm-utils/src/evm_runner.rs
@@ -0,0 +1,166 @@
+use std::{convert::Infallible, fmt::Debug, fs::File, io::Read};
+
+use revm::{
+ primitives::{address, Address, EVMError, ExecutionResult, Output, TxKind, U256},
+ Evm, InMemoryDB,
+};
+use revm_primitives::{AccountInfo, Bytecode, Bytes, Log};
+use thiserror::Error;
+
+use crate::{compilation::source_to_bytecode, repo_root_dir};
+
+/// Evm runner errors
+#[derive(Debug, Error)]
+#[error(transparent)]
+#[non_exhaustive]
+#[allow(missing_docs)]
+pub enum EvmRunnerError {
+ #[error("Evm transaction reverted")]
+ Revert(ExecutionResult),
+
+ #[error("Evm transaction trapped")]
+ Halt(ExecutionResult),
+
+ #[error("Account does not exist")]
+ AccountDoesNotExists(Address),
+
+ #[error("Address does not have bytecode")]
+ AddressDoesNotHaveBytecode(Address),
+
+ #[error("Evm execution error")]
+ EvmExecution(#[from] EVMError),
+}
+
+pub struct SuccessResult {
+ pub gas_used: u64,
+ pub output: Vec,
+ pub logs: Vec,
+}
+
+/// Evm runner.
+#[derive(Debug)]
+pub struct EvmRunner {
+ pub db: InMemoryDB,
+}
+
+fn get_precompile_source() -> String {
+ let mut source = String::new();
+ let mut file = File::open(repo_root_dir().join("contracts/ArbSysMock.sol"))
+ .expect("Cannot open contract source file");
+ file.read_to_string(&mut source)
+ .expect("Cannot read contract source file");
+ source
+}
+
+impl EvmRunner {
+ pub fn aleph_evm() -> Self {
+ let mut db = InMemoryDB::default();
+
+ let precompiles_bytecode = source_to_bytecode(get_precompile_source(), "ArbSysMock", true);
+ db.insert_account_info(
+ address!("0000000000000000000000000000000000000064"),
+ AccountInfo::from_bytecode(Bytecode::new_raw(Bytes::from(precompiles_bytecode))),
+ );
+
+ Self { db }
+ }
+
+ /// Return code size of given address.
+ pub fn code_size(&self, address: Address) -> Result {
+ Ok(self
+ .db
+ .accounts
+ .get(&address)
+ .ok_or(EvmRunnerError::AccountDoesNotExists(address))?
+ .info
+ .code
+ .clone()
+ .ok_or(EvmRunnerError::AddressDoesNotHaveBytecode(address))?
+ .len())
+ }
+
+ /// Apply `create` transaction with given `bytecode` as creation bytecode. Return created
+ /// `address`.
+ pub fn create(
+ &mut self,
+ bytecode: Vec,
+ caller: Option,
+ ) -> Result {
+ let mut evm = Evm::builder()
+ .with_db(&mut self.db)
+ .modify_tx_env(|tx| {
+ tx.caller = caller.unwrap_or(address!("0000000000000000000000000000000000000000"));
+ tx.gas_limit = u64::MAX;
+ tx.transact_to = TxKind::Create;
+ tx.data = bytecode.into();
+ tx.chain_id = Some(1);
+ })
+ .modify_cfg_env(|env| {
+ env.limit_contract_code_size = Some(0x17700);
+ }) // ~96kb
+ .build();
+
+ let result = evm.transact_commit()?;
+
+ match result {
+ ExecutionResult::Success { output, .. } => match output {
+ Output::Create(_, Some(address)) => Ok(address),
+ _ => unreachable!(),
+ },
+ ExecutionResult::Revert { .. } => Err(EvmRunnerError::Revert(result)),
+ ExecutionResult::Halt { .. } => Err(EvmRunnerError::Halt(result)),
+ }
+ }
+
+ /// Apply `call` transaction to given `address` with `calldata`. Return a tuple of `gas_used`
+ /// and `return_data`.
+ pub fn call(
+ &mut self,
+ address: Address,
+ calldata: Vec,
+ caller: Option,
+ value: Option,
+ ) -> Result {
+ let mut evm = Evm::builder()
+ .with_db(&mut self.db)
+ .modify_tx_env(|tx| {
+ tx.caller = caller.unwrap_or(address!("0000000000000000000000000000000000000000"));
+ tx.gas_limit = u64::MAX;
+ tx.transact_to = TxKind::Call(address);
+ tx.data = calldata.into();
+ tx.value = U256::from(value.unwrap_or(U256::ZERO));
+ tx.chain_id = Some(1);
+ })
+ .build();
+
+ let result = evm.transact_commit()?;
+
+ match result {
+ ExecutionResult::Success {
+ output,
+ gas_used,
+ logs,
+ ..
+ } => match output {
+ Output::Call(value) => Ok(SuccessResult {
+ gas_used,
+ output: value.into(),
+ logs,
+ }),
+ _ => unreachable!(),
+ },
+ ExecutionResult::Revert { .. } => Err(EvmRunnerError::Revert(result)),
+ ExecutionResult::Halt { .. } => Err(EvmRunnerError::Halt(result)),
+ }
+ }
+
+ pub fn get_balance(&self, address: Address) -> Result {
+ Ok(self
+ .db
+ .accounts
+ .get(&address)
+ .ok_or(EvmRunnerError::AccountDoesNotExists(address))?
+ .info
+ .balance)
+ }
+}
diff --git a/crates/evm-utils/src/lib.rs b/crates/evm-utils/src/lib.rs
new file mode 100644
index 00000000..f90ce47f
--- /dev/null
+++ b/crates/evm-utils/src/lib.rs
@@ -0,0 +1,21 @@
+use std::{env, fs, path::PathBuf};
+
+pub use evm_runner::{EvmRunner, EvmRunnerError, SuccessResult};
+pub use revm_primitives;
+
+pub mod compilation;
+mod evm_runner;
+
+fn repo_root_dir() -> PathBuf {
+ let mut current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
+
+ while current_dir.pop() {
+ if let Ok(contents) = fs::read_to_string(current_dir.join("Cargo.toml")) {
+ if contents.contains("[workspace]") {
+ return current_dir;
+ }
+ }
+ }
+
+ unreachable!("No workspace directory found")
+}
diff --git a/crates/halo2-verifier/Acknowledgements b/crates/halo2-verifier/Acknowledgements
new file mode 100644
index 00000000..692d26a7
--- /dev/null
+++ b/crates/halo2-verifier/Acknowledgements
@@ -0,0 +1 @@
+Adopted from https://github.com/privacy-scaling-explorations/halo2-solidity-verifier
\ No newline at end of file
diff --git a/crates/halo2-verifier/Cargo.toml b/crates/halo2-verifier/Cargo.toml
new file mode 100644
index 00000000..9312316a
--- /dev/null
+++ b/crates/halo2-verifier/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "halo2_solidity_verifier"
+version = "0.2.0"
+edition = "2021"
+
+[lib]
+name = "halo2_solidity_verifier"
+path = "src/lib/lib.rs"
+
+[[bin]]
+name = "halo2_solidity_verifier_generator"
+path = "src/generator.rs"
+
+[dependencies]
+alloy-primitives = { workspace = true }
+alloy-sol-types = { workspace = true }
+askama = { workspace = true, features = ["config"] }
+evm-utils = { workspace = true }
+halo2_proofs = { workspace = true }
+itertools = { workspace = true }
+rand = { workspace = true, features = ["small_rng"] }
+ruint = { workspace = true }
+shielder-circuits = { workspace = true }
+shielder-rust-sdk = { workspace = true, features = ["parameter_generation", "powers_of_tau", "conversion"] }
diff --git a/crates/halo2-verifier/LICENSE b/crates/halo2-verifier/LICENSE
new file mode 100644
index 00000000..245499ec
--- /dev/null
+++ b/crates/halo2-verifier/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Privacy & Scaling Explorations (formerly known as appliedzkp)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/crates/halo2-verifier/Makefile b/crates/halo2-verifier/Makefile
new file mode 100644
index 00000000..abf8daa4
--- /dev/null
+++ b/crates/halo2-verifier/Makefile
@@ -0,0 +1,15 @@
+.PHONY: build
+build: ## Build the project
+ @cargo build --release
+
+.PHONY: test
+test: ## Run tests
+ @cargo test -- --nocapture
+
+.PHONY: lint
+lint: ## Run clippy and fmt
+ @cargo clippy --release -- -D warnings
+ @cargo +nightly fmt --all
+
+help: ## Displays this help
+ @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
diff --git a/crates/halo2-verifier/askama.toml b/crates/halo2-verifier/askama.toml
new file mode 100644
index 00000000..44f2f2f1
--- /dev/null
+++ b/crates/halo2-verifier/askama.toml
@@ -0,0 +1,3 @@
+[[escaper]]
+path = "askama::Text"
+extensions = ["sol"]
diff --git a/crates/halo2-verifier/src/generator.rs b/crates/halo2-verifier/src/generator.rs
new file mode 100644
index 00000000..43e5b44c
--- /dev/null
+++ b/crates/halo2-verifier/src/generator.rs
@@ -0,0 +1,164 @@
+use std::{fs::File, io::Write, path::PathBuf, str};
+
+use halo2_proofs::{
+ halo2curves::bn256::{Bn256, Fr},
+ poly::kzg::commitment::ParamsKZG,
+};
+use halo2_solidity_verifier::{BatchOpenScheme::Bdfg21, SolidityGenerator};
+use shielder_circuits::{
+ circuits::{generate_keys_with_min_k, Params},
+ consts::RANGE_PROOF_CHUNK_SIZE,
+ deposit::DepositProverKnowledge,
+ new_account::NewAccountProverKnowledge,
+ withdraw::WithdrawProverKnowledge,
+ EnumCount, ProverKnowledge, MAX_K,
+};
+use shielder_rust_sdk::powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format};
+
+const CONTRACTS_DIR: &str = "./contracts";
+
+pub fn main() {
+ let full_parameters = read_setup_parameters(
+ get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau),
+ Format::PerpetualPowersOfTau,
+ )
+ .expect("failed to read parameters from the ptau file");
+
+ handle_relation::>(full_parameters.clone(), "NewAccount");
+ handle_relation::>(
+ full_parameters.clone(),
+ "Deposit",
+ );
+ handle_relation::>(
+ full_parameters,
+ "Withdraw",
+ );
+}
+
+/// Generate verification key and proving key contracts for the given circuit type.
+fn handle_relation>(full_params: Params, relation: &str) {
+ println!("Generating {relation} relation contracts...");
+ let (verifier_solidity, vk_solidity) = generate_solidity_verification_bundle::(full_params);
+ save_contract_source(&format!("{relation}Verifier.sol"), &verifier_solidity);
+ save_contract_source(&format!("{relation}VerifyingKey.sol"), &vk_solidity);
+}
+
+/// Given trusted setup, generate Solidity code for the verification key and the verifier.
+fn generate_solidity_verification_bundle>(
+ full_parameters: ParamsKZG,
+) -> (String, String) {
+ let (parameters, _, _, vk) =
+ generate_keys_with_min_k::(full_parameters).expect("Failed to generate keys");
+ SolidityGenerator::new(¶meters, &vk, Bdfg21, PK::PublicInput::COUNT)
+ .render_separately()
+ .expect("Failed to generate separate contracts")
+}
+
+/// Writes solidity source code to the file under `CONTRACTS_DIR` directory.
+fn save_contract_source(filename: &str, solidity: &str) {
+ let path = PathBuf::from(format!("{CONTRACTS_DIR}/{filename}"));
+ File::create(path)
+ .unwrap()
+ .write_all(solidity.as_bytes())
+ .expect("Can write to file");
+}
+
+#[cfg(test)]
+mod test {
+ use alloy_primitives::Address;
+ use alloy_sol_types::SolValue;
+ use evm_utils::{compilation::source_to_bytecode, EvmRunner, EvmRunnerError, SuccessResult};
+ use halo2_proofs::halo2curves::bn256::Fr;
+ use halo2_solidity_verifier::verifier_contract;
+ use shielder_circuits::{
+ circuits::{generate_proof, generate_setup_params},
+ consts::{MAX_K, RANGE_PROOF_CHUNK_SIZE},
+ deposit::DepositProverKnowledge,
+ generate_keys_with_min_k,
+ new_account::NewAccountProverKnowledge,
+ withdraw::WithdrawProverKnowledge,
+ ProverKnowledge,
+ };
+ use shielder_rust_sdk::parameter_generation::rng;
+
+ use crate::generate_solidity_verification_bundle;
+
+ // constants to safeguard against regressions, 110% of MEASURED_GAS
+ pub const NEW_ACCOUNT_VERIFICATION_GAS_COST: u64 = 706212; //1.1 * 642011;
+ pub const DEPOSIT_VERIFICATION_GAS_COST: u64 = 914940; //1.1 * 831764;
+ pub const WITHDRAW_VERIFICATION_GAS_COST: u64 = 1017855; //1.1 * 925323;
+
+ fn deploy_source_code(source: &str, contract_name: &str, evm: &mut EvmRunner) -> Address {
+ let bytecode = source_to_bytecode(source, contract_name, true);
+ evm.create(bytecode, None)
+ .expect("Contract can be deployed")
+ }
+
+ /// Verify proof and return the gas used
+ ///
+ /// Return an error if verifier fails on-chain.
+ fn verify_with_contract(
+ verifier_solidity: &str,
+ vk_solidity: &str,
+ proof: &[u8],
+ public_input: &[Fr],
+ ) -> Result {
+ let mut evm = EvmRunner::aleph_evm();
+
+ // Deploy verifier and vk contracts
+ let verifier_address = deploy_source_code(verifier_solidity, "Halo2Verifier", &mut evm);
+ let vk_address = deploy_source_code(vk_solidity, "Halo2VerifyingKey", &mut evm);
+
+ // Call verifier contract
+ let calldata = verifier_contract::encode_calldata(vk_address, proof, public_input);
+ match evm.call(verifier_address, calldata, None, None) {
+ Ok(SuccessResult {
+ gas_used, output, ..
+ }) => {
+ println!("Gas cost of verifying: {gas_used}");
+ assert!(::abi_decode(&output, true).unwrap());
+ Ok(gas_used)
+ }
+ Err(why) => Err(why),
+ }
+ }
+
+ // Generate proof for an example relation instance and verify it with the Solidity contract.
+ fn prove_and_verify>(cost_upper_bound: u64) {
+ let mut rng = rng();
+ let full_parameters = generate_setup_params(MAX_K, &mut rng);
+ let prover_knowledge = PK::random_correct_example(&mut rng);
+ let public_input = prover_knowledge.serialize_public_input();
+
+ let (verifier_solidity, vk_solidity) =
+ generate_solidity_verification_bundle::(full_parameters.clone());
+
+ let (parameters, _, pk, _) =
+ generate_keys_with_min_k::(full_parameters).unwrap();
+ let circuit = prover_knowledge.create_circuit();
+ let proof = generate_proof(¶meters, &pk, circuit, &public_input, &mut rng);
+
+ let result = verify_with_contract(&verifier_solidity, &vk_solidity, &proof, &public_input);
+ assert!(result.is_ok());
+ assert!(result.unwrap() <= cost_upper_bound);
+ }
+
+ #[test]
+ fn prove_and_verify_new_account() {
+ prove_and_verify::>(NEW_ACCOUNT_VERIFICATION_GAS_COST);
+ }
+
+ #[test]
+ fn prove_and_verify_deposit() {
+ prove_and_verify::>(
+ DEPOSIT_VERIFICATION_GAS_COST,
+ );
+ }
+
+ #[test]
+ fn prove_and_verify_withdraw() {
+ prove_and_verify::>(
+ WITHDRAW_VERIFICATION_GAS_COST,
+ );
+ }
+}
diff --git a/crates/halo2-verifier/src/lib/codegen.rs b/crates/halo2-verifier/src/lib/codegen.rs
new file mode 100644
index 00000000..c23f23f0
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen.rs
@@ -0,0 +1,302 @@
+use std::fmt::{self, Debug};
+
+use halo2_proofs::{
+ halo2curves::{bn256, ff::Field},
+ plonk::VerifyingKey,
+ poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG, Rotation},
+};
+use itertools::{chain, Itertools};
+pub use pcs::BatchOpenScheme;
+use ruint::aliases::U256;
+use shielder_rust_sdk::conversion::field_to_u256;
+
+use crate::codegen::{
+ evaluator::Evaluator,
+ template::{Halo2Verifier, Halo2VerifyingKey},
+ util::{g1_to_u256s, g2_to_u256s, ConstraintSystemMeta, Data, Ptr},
+};
+
+mod evaluator;
+mod pcs;
+mod template;
+pub(crate) mod util;
+
+/// Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254.
+#[derive(Debug)]
+pub struct SolidityGenerator<'a> {
+ params: &'a ParamsKZG,
+ vk: &'a VerifyingKey,
+ scheme: BatchOpenScheme,
+ num_instances: usize,
+ acc_encoding: Option,
+ meta: ConstraintSystemMeta,
+}
+
+/// KZG accumulator encoding information.
+/// Limbs of each field element are assumed to be least significant limb first.
+///
+/// Given instances and `AccumulatorEncoding`, the accumulator will be interpreted as below:
+/// ```rust
+/// use halo2_proofs::halo2curves::{bn256, ff::{Field, PrimeField}, CurveAffine};
+///
+/// fn accumulator_from_limbs(
+/// instances: &[bn256::Fr],
+/// offset: usize,
+/// num_limbs: usize,
+/// num_limb_bits: usize,
+/// ) -> (bn256::G1Affine, bn256::G1Affine) {
+/// let limbs = |offset| &instances[offset..offset + num_limbs];
+/// let acc_lhs_x = fe_from_limbs(limbs(offset), num_limb_bits);
+/// let acc_lhs_y = fe_from_limbs(limbs(offset + num_limbs), num_limb_bits);
+/// let acc_rhs_x = fe_from_limbs(limbs(offset + 2 * num_limbs), num_limb_bits);
+/// let acc_rhs_y = fe_from_limbs(limbs(offset + 3 * num_limbs), num_limb_bits);
+/// let acc_lhs = bn256::G1Affine::from_xy(acc_lhs_x, acc_lhs_y).unwrap();
+/// let acc_rhs = bn256::G1Affine::from_xy(acc_rhs_x, acc_rhs_y).unwrap();
+/// (acc_lhs, acc_rhs)
+/// }
+///
+/// fn fe_from_limbs(limbs: &[bn256::Fr], num_limb_bits: usize) -> bn256::Fq {
+/// limbs.iter().rev().fold(bn256::Fq::ZERO, |acc, limb| {
+/// acc * bn256::Fq::from(2).pow_vartime([num_limb_bits as u64])
+/// + bn256::Fq::from_repr_vartime(limb.to_repr()).unwrap()
+/// })
+/// }
+/// ```
+///
+/// In the end of `verifyProof`, the accumulator will be used to do batched pairing with the
+/// pairing input of incoming proof.
+#[derive(Clone, Copy, Debug)]
+pub struct AccumulatorEncoding {
+ /// Offset of accumulator limbs in instances.
+ pub offset: usize,
+ /// Number of limbs per base field element.
+ pub num_limbs: usize,
+ /// Number of bits per limb.
+ pub num_limb_bits: usize,
+}
+
+impl AccumulatorEncoding {
+ /// Return a new `AccumulatorEncoding`.
+ pub fn new(offset: usize, num_limbs: usize, num_limb_bits: usize) -> Self {
+ Self {
+ offset,
+ num_limbs,
+ num_limb_bits,
+ }
+ }
+}
+
+impl<'a> SolidityGenerator<'a> {
+ /// Return a new `SolidityGenerator`.
+ pub fn new(
+ params: &'a ParamsKZG,
+ vk: &'a VerifyingKey,
+ scheme: BatchOpenScheme,
+ num_instances: usize,
+ ) -> Self {
+ assert_ne!(vk.cs().num_advice_columns(), 0);
+ assert!(
+ vk.cs().num_instance_columns() <= 1,
+ "Multiple instance columns is not yet implemented"
+ );
+ assert!(
+ !vk.cs()
+ .instance_queries()
+ .iter()
+ .any(|(_, rotation)| *rotation != Rotation::cur()),
+ "Rotated query to instance column is not yet implemented"
+ );
+
+ Self {
+ params,
+ vk,
+ scheme,
+ num_instances,
+ acc_encoding: None,
+ meta: ConstraintSystemMeta::new(vk.cs()),
+ }
+ }
+
+ /// Set `AccumulatorEncoding`.
+ pub fn set_acc_encoding(mut self, acc_encoding: Option) -> Self {
+ self.acc_encoding = acc_encoding;
+ self
+ }
+}
+
+impl<'a> SolidityGenerator<'a> {
+ /// Render `Halo2Verifier.sol` with verifying key embedded into writer.
+ pub fn render_into(&self, verifier_writer: &mut impl fmt::Write) -> Result<(), fmt::Error> {
+ self.generate_verifier(false).render(verifier_writer)
+ }
+
+ /// Render `Halo2Verifier.sol` with verifying key embedded and return it as `String`.
+ pub fn render(&self) -> Result {
+ let mut verifier_output = String::new();
+ self.render_into(&mut verifier_output)?;
+ Ok(verifier_output)
+ }
+
+ /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` into writers.
+ pub fn render_separately_into(
+ &self,
+ verifier_writer: &mut impl fmt::Write,
+ vk_writer: &mut impl fmt::Write,
+ ) -> Result<(), fmt::Error> {
+ self.generate_verifier(true).render(verifier_writer)?;
+ self.generate_vk().render(vk_writer)?;
+ Ok(())
+ }
+
+ /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` and return them as `String`.
+ pub fn render_separately(&self) -> Result<(String, String), fmt::Error> {
+ let mut verifier_output = String::new();
+ let mut vk_output = String::new();
+ self.render_separately_into(&mut verifier_output, &mut vk_output)?;
+ Ok((verifier_output, vk_output))
+ }
+
+ fn generate_vk(&self) -> Halo2VerifyingKey {
+ let constants = {
+ let domain = self.vk.get_domain();
+ let vk_digest = field_to_u256(self.vk.transcript_repr());
+ let num_instances = U256::from(self.num_instances);
+ let k = U256::from(domain.k());
+ let n_inv = field_to_u256(bn256::Fr::from(1 << domain.k()).invert().unwrap());
+ let omega = field_to_u256(domain.get_omega());
+ let omega_inv = field_to_u256(domain.get_omega_inv());
+ let omega_inv_to_l = {
+ let l = self.meta.rotation_last.unsigned_abs() as u64;
+ field_to_u256(domain.get_omega_inv().pow_vartime([l]))
+ };
+ let has_accumulator = U256::from(self.acc_encoding.is_some() as usize);
+ let acc_offset = self
+ .acc_encoding
+ .map(|acc_encoding| U256::from(acc_encoding.offset))
+ .unwrap_or_default();
+ let num_acc_limbs = self
+ .acc_encoding
+ .map(|acc_encoding| U256::from(acc_encoding.num_limbs))
+ .unwrap_or_default();
+ let num_acc_limb_bits = self
+ .acc_encoding
+ .map(|acc_encoding| U256::from(acc_encoding.num_limb_bits))
+ .unwrap_or_default();
+ let g1 = self.params.get_g()[0];
+ let g1 = g1_to_u256s(g1);
+ let g2 = g2_to_u256s(self.params.g2());
+ let neg_s_g2 = g2_to_u256s(-self.params.s_g2());
+ vec![
+ ("vk_digest", vk_digest),
+ ("num_instances", num_instances),
+ ("k", k),
+ ("n_inv", n_inv),
+ ("omega", omega),
+ ("omega_inv", omega_inv),
+ ("omega_inv_to_l", omega_inv_to_l),
+ ("has_accumulator", has_accumulator),
+ ("acc_offset", acc_offset),
+ ("num_acc_limbs", num_acc_limbs),
+ ("num_acc_limb_bits", num_acc_limb_bits),
+ ("g1_x", g1[0]),
+ ("g1_y", g1[1]),
+ ("g2_x_1", g2[0]),
+ ("g2_x_2", g2[1]),
+ ("g2_y_1", g2[2]),
+ ("g2_y_2", g2[3]),
+ ("neg_s_g2_x_1", neg_s_g2[0]),
+ ("neg_s_g2_x_2", neg_s_g2[1]),
+ ("neg_s_g2_y_1", neg_s_g2[2]),
+ ("neg_s_g2_y_2", neg_s_g2[3]),
+ ]
+ };
+ let fixed_comms = chain![self.vk.fixed_commitments()]
+ .flat_map(g1_to_u256s)
+ .tuples()
+ .collect();
+ let permutation_comms = chain![self.vk.permutation().commitments()]
+ .flat_map(g1_to_u256s)
+ .tuples()
+ .collect();
+ Halo2VerifyingKey {
+ constants,
+ fixed_comms,
+ permutation_comms,
+ }
+ }
+
+ fn generate_verifier(&self, separate: bool) -> Halo2Verifier {
+ let proof_cptr = Ptr::calldata(if separate { 0x84 } else { 0x64 });
+
+ let vk = self.generate_vk();
+ let vk_len = vk.len();
+ let vk_mptr = Ptr::memory(self.static_working_memory_size(&vk, proof_cptr));
+ let data = Data::new(&self.meta, &vk, vk_mptr, proof_cptr);
+
+ let evaluator = Evaluator::new(self.vk.cs(), &self.meta, &data);
+ let quotient_eval_numer_computations = chain![
+ evaluator.gate_computations(),
+ evaluator.permutation_computations(),
+ evaluator.lookup_computations()
+ ]
+ .enumerate()
+ .map(|(idx, (mut lines, var))| {
+ let line = if idx == 0 {
+ format!("quotient_eval_numer := {var}")
+ } else {
+ format!(
+ "quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), {var}, r)"
+ )
+ };
+ lines.push(line);
+ lines
+ })
+ .collect();
+
+ let pcs_computations = self.scheme.computations(&self.meta, &data);
+
+ Halo2Verifier {
+ scheme: self.scheme,
+ embedded_vk: (!separate).then_some(vk),
+ vk_len,
+ vk_mptr,
+ num_neg_lagranges: self.meta.rotation_last.unsigned_abs() as usize,
+ num_advices: self.meta.num_advices(),
+ num_challenges: self.meta.num_challenges(),
+ num_rotations: self.meta.num_rotations,
+ num_evals: self.meta.num_evals,
+ num_quotients: self.meta.num_quotients,
+ proof_cptr,
+ quotient_comm_cptr: data.quotient_comm_cptr,
+ proof_len: self.meta.proof_len(self.scheme),
+ challenge_mptr: data.challenge_mptr,
+ theta_mptr: data.theta_mptr,
+ quotient_eval_numer_computations,
+ pcs_computations,
+ }
+ }
+
+ fn static_working_memory_size(&self, vk: &Halo2VerifyingKey, proof_cptr: Ptr) -> usize {
+ let pcs_computation = {
+ let mock_vk_mptr = Ptr::memory(0x100000);
+ let mock = Data::new(&self.meta, vk, mock_vk_mptr, proof_cptr);
+ self.scheme.static_working_memory_size(&self.meta, &mock)
+ };
+
+ itertools::max([
+ // Keccak256 input (can overwrite vk)
+ itertools::max(chain![
+ self.meta.num_advices().into_iter().map(|n| n * 2 + 1),
+ [self.meta.num_evals + 1],
+ ])
+ .unwrap()
+ .saturating_sub(vk.len() / 0x20),
+ // PCS computation
+ pcs_computation,
+ // Pairing
+ 12,
+ ])
+ .unwrap()
+ * 0x20
+ }
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/evaluator.rs b/crates/halo2-verifier/src/lib/codegen/evaluator.rs
new file mode 100644
index 00000000..814be370
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/evaluator.rs
@@ -0,0 +1,373 @@
+#![allow(clippy::useless_format)]
+
+use std::{cell::RefCell, cmp::Ordering, collections::HashMap, iter};
+
+use halo2_proofs::{
+ halo2curves::ff::PrimeField,
+ plonk::{
+ Advice, AdviceQuery, Any, Challenge, ConstraintSystem, Expression, Fixed, FixedQuery, Gate,
+ InstanceQuery,
+ },
+};
+use itertools::{chain, izip, Itertools};
+use ruint::aliases::U256;
+use shielder_rust_sdk::conversion::field_to_u256;
+
+use crate::codegen::util::{code_block, ConstraintSystemMeta, Data};
+
+#[derive(Debug)]
+pub(crate) struct Evaluator<'a, F: PrimeField> {
+ cs: &'a ConstraintSystem,
+ meta: &'a ConstraintSystemMeta,
+ data: &'a Data,
+ var_counter: RefCell,
+ var_cache: RefCell>,
+}
+
+impl<'a, F> Evaluator<'a, F>
+where
+ F: PrimeField,
+{
+ pub(crate) fn new(
+ cs: &'a ConstraintSystem,
+ meta: &'a ConstraintSystemMeta,
+ data: &'a Data,
+ ) -> Self {
+ Self {
+ cs,
+ meta,
+ data,
+ var_counter: Default::default(),
+ var_cache: Default::default(),
+ }
+ }
+
+ pub fn gate_computations(&self) -> Vec<(Vec, String)> {
+ self.cs
+ .gates()
+ .iter()
+ .flat_map(Gate::polynomials)
+ .map(|expression| self.evaluate_and_reset(expression))
+ .collect()
+ }
+
+ pub fn permutation_computations(&self) -> Vec<(Vec, String)> {
+ let Self { meta, data, .. } = self;
+ let last_chunk_idx = meta.num_permutation_zs - 1;
+ chain![
+ data.permutation_z_evals.first().map(|(z, _, _)| {
+ vec![
+ format!("let l_0 := mload(L_0_MPTR)"),
+ format!("let eval := addmod(l_0, sub(r, mulmod(l_0, {z}, r)), r)"),
+ ]
+ }),
+ data.permutation_z_evals.last().map(|(z, _, _)| {
+ let item = "addmod(mulmod(perm_z_last, perm_z_last, r), sub(r, perm_z_last), r)";
+ vec![
+ format!("let perm_z_last := {z}"),
+ format!("let eval := mulmod(mload(L_LAST_MPTR), {item}, r)"),
+ ]
+ }),
+ data.permutation_z_evals.iter().tuple_windows().map(
+ |((_, _, z_i_last), (z_j, _, _))| {
+ let item = format!("addmod({z_j}, sub(r, {z_i_last}), r)");
+ vec![format!("let eval := mulmod(mload(L_0_MPTR), {item}, r)")]
+ }
+ ),
+ izip!(
+ meta.permutation_columns.chunks(meta.permutation_chunk_len),
+ &data.permutation_z_evals,
+ )
+ .enumerate()
+ .map(|(chunk_idx, (columns, evals))| {
+ let last_column_idx = columns.len() - 1;
+ chain![
+ [
+ format!("let gamma := mload(GAMMA_MPTR)"),
+ format!("let beta := mload(BETA_MPTR)"),
+ format!("let lhs := {}", evals.1),
+ format!("let rhs := {}", evals.0),
+ ],
+ columns.iter().flat_map(|column| {
+ let perm_eval = &data.permutation_evals[column];
+ let eval = self.eval(*column.column_type(), column.index(), 0);
+ let item = format!("mulmod(beta, {perm_eval}, r)");
+ [format!(
+ "lhs := mulmod(lhs, addmod(addmod({eval}, {item}, r), gamma, r), r)"
+ )]
+ }),
+ (chunk_idx == 0)
+ .then(|| "mstore(0x00, mulmod(beta, mload(X_MPTR), r))".to_string()),
+ columns.iter().enumerate().flat_map(|(idx, column)| {
+ let eval = self.eval(*column.column_type(), column.index(), 0);
+ let item = format!("addmod(addmod({eval}, mload(0x00), r), gamma, r)");
+ chain![
+ [format!("rhs := mulmod(rhs, {item}, r)")],
+ (!(chunk_idx == last_chunk_idx && idx == last_column_idx))
+ .then(|| "mstore(0x00, mulmod(mload(0x00), delta, r))".to_string()),
+ ]
+ }),
+ {
+ let item = format!("addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)");
+ let item = format!("sub(r, mulmod(left_sub_right, {item}, r))");
+ [
+ format!("let left_sub_right := addmod(lhs, sub(r, rhs), r)"),
+ format!("let eval := addmod(left_sub_right, {item}, r)"),
+ ]
+ }
+ ]
+ .collect_vec()
+ })
+ ]
+ .zip(iter::repeat("eval".to_string()))
+ .collect()
+ }
+
+ pub fn lookup_computations(&self) -> Vec<(Vec, String)> {
+ let input_tables = self
+ .cs
+ .lookups()
+ .iter()
+ .map(|lookup| {
+ let [(input_lines, inputs), (table_lines, tables)] =
+ [lookup.input_expressions(), lookup.table_expressions()].map(|expressions| {
+ let (lines, inputs) = expressions
+ .iter()
+ .map(|expression| self.evaluate(expression))
+ .fold((Vec::new(), Vec::new()), |mut acc, result| {
+ acc.0.extend(result.0);
+ acc.1.push(result.1);
+ acc
+ });
+ self.reset();
+ (lines, inputs)
+ });
+ (input_lines, inputs, table_lines, tables)
+ })
+ .collect_vec();
+ izip!(input_tables, &self.data.lookup_evals)
+ .flat_map(|(input_table, evals)| {
+ let (input_lines, inputs, table_lines, tables) = input_table;
+ let (input_0, rest_inputs) = inputs.split_first().unwrap();
+ let (table_0, rest_tables) = tables.split_first().unwrap();
+ let (z, z_next, p_input, p_input_prev, p_table) = evals;
+ [
+ vec![
+ format!("let l_0 := mload(L_0_MPTR)"),
+ format!("let eval := addmod(l_0, mulmod(l_0, sub(r, {z}), r), r)"),
+ ],
+ {
+ let item = format!("addmod(mulmod({z}, {z}, r), sub(r, {z}), r)");
+ vec![
+ format!("let l_last := mload(L_LAST_MPTR)"),
+ format!("let eval := mulmod(l_last, {item}, r)"),
+ ]
+ },
+ chain![
+ ["let theta := mload(THETA_MPTR)", "let input"].map(str::to_string),
+ code_block::<1, false>(chain![
+ input_lines,
+ [format!("input := {input_0}")],
+ rest_inputs.iter().map(|input| format!(
+ "input := addmod(mulmod(input, theta, r), {input}, r)"
+ ))
+ ]),
+ ["let table"].map(str::to_string),
+ code_block::<1, false>(chain![
+ table_lines,
+ [format!("table := {table_0}")],
+ rest_tables.iter().map(|table| format!(
+ "table := addmod(mulmod(table, theta, r), {table}, r)"
+ ))
+ ]),
+ {
+ let lhs = format!("addmod({p_input}, beta, r)");
+ let rhs = format!("addmod({p_table}, gamma, r)");
+ let permuted = format!("mulmod({lhs}, {rhs}, r)");
+ let input =
+ "mulmod(addmod(input, beta, r), addmod(table, gamma, r), r)";
+ [
+ format!("let beta := mload(BETA_MPTR)"),
+ format!("let gamma := mload(GAMMA_MPTR)"),
+ format!("let lhs := mulmod({z_next}, {permuted}, r)"),
+ format!("let rhs := mulmod({z}, {input}, r)"),
+ ]
+ },
+ {
+ let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)";
+ let l_active = format!("addmod(1, sub(r, {l_inactive}), r)");
+ [format!(
+ "let eval := mulmod({l_active}, addmod(lhs, sub(r, rhs), r), r)"
+ )]
+ },
+ ]
+ .collect_vec(),
+ {
+ let l_0 = "mload(L_0_MPTR)";
+ let item = format!("addmod({p_input}, sub(r, {p_table}), r)");
+ vec![format!("let eval := mulmod({l_0}, {item}, r)")]
+ },
+ {
+ let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)";
+ let l_active = format!("addmod(1, sub(r, {l_inactive}), r)");
+ let lhs = format!("addmod({p_input}, sub(r, {p_table}), r)");
+ let rhs = format!("addmod({p_input}, sub(r, {p_input_prev}), r)");
+ vec![format!(
+ "let eval := mulmod({l_active}, mulmod({lhs}, {rhs}, r), r)"
+ )]
+ },
+ ]
+ })
+ .zip(iter::repeat("eval".to_string()))
+ .collect_vec()
+ }
+
+ fn eval(&self, column_type: impl Into, column_index: usize, rotation: i32) -> String {
+ match column_type.into() {
+ Any::Advice(_) => self.data.advice_evals[&(column_index, rotation)].to_string(),
+ Any::Fixed => self.data.fixed_evals[&(column_index, rotation)].to_string(),
+ Any::Instance => self.data.instance_eval.to_string(),
+ }
+ }
+
+ fn reset(&self) {
+ *self.var_counter.borrow_mut() = Default::default();
+ *self.var_cache.borrow_mut() = Default::default();
+ }
+
+ fn evaluate_and_reset(&self, expression: &Expression) -> (Vec, String) {
+ let result = self.evaluate(expression);
+ self.reset();
+ result
+ }
+
+ fn evaluate(&self, expression: &Expression) -> (Vec, String) {
+ evaluate(
+ expression,
+ &|constant| {
+ let constant = u256_string(constant);
+ self.init_var(constant, None)
+ },
+ &|query| {
+ self.init_var(
+ self.eval(Fixed, query.column_index(), query.rotation().0),
+ Some(fixed_eval_var(query)),
+ )
+ },
+ &|query| {
+ self.init_var(
+ self.eval(Advice::default(), query.column_index(), query.rotation().0),
+ Some(advice_eval_var(query)),
+ )
+ },
+ &|_| self.init_var(self.data.instance_eval, Some("i_eval".to_string())),
+ &|challenge| {
+ self.init_var(
+ self.data.challenges[challenge.index()],
+ Some(format!("c_{}", challenge.index())),
+ )
+ },
+ &|(mut acc, var)| {
+ let (lines, var) = self.init_var(format!("sub(r, {var})"), None);
+ acc.extend(lines);
+ (acc, var)
+ },
+ &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| {
+ let (lines, var) = self.init_var(format!("addmod({lhs_var}, {rhs_var}, r)"), None);
+ lhs_acc.extend(rhs_acc);
+ lhs_acc.extend(lines);
+ (lhs_acc, var)
+ },
+ &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| {
+ let (lines, var) = self.init_var(format!("mulmod({lhs_var}, {rhs_var}, r)"), None);
+ lhs_acc.extend(rhs_acc);
+ lhs_acc.extend(lines);
+ (lhs_acc, var)
+ },
+ &|(mut acc, var), scalar| {
+ let scalar = u256_string(scalar);
+ let (lines, var) = self.init_var(format!("mulmod({var}, {scalar}, r)"), None);
+ acc.extend(lines);
+ (acc, var)
+ },
+ )
+ }
+
+ fn init_var(&self, value: impl ToString, var: Option) -> (Vec, String) {
+ let value = value.to_string();
+ if self.var_cache.borrow().contains_key(&value) {
+ (vec![], self.var_cache.borrow()[&value].clone())
+ } else {
+ let var = var.unwrap_or_else(|| self.next_var());
+ self.var_cache
+ .borrow_mut()
+ .insert(value.clone(), var.clone());
+ (vec![format!("let {var} := {value}")], var)
+ }
+ }
+
+ fn next_var(&self) -> String {
+ let count = *self.var_counter.borrow();
+ *self.var_counter.borrow_mut() += 1;
+ format!("var{count}")
+ }
+}
+
+fn u256_string(value: U256) -> String {
+ if value.bit_len() < 64 {
+ format!("0x{:x}", value.as_limbs()[0])
+ } else {
+ format!("0x{value:x}")
+ }
+}
+
+fn fixed_eval_var(fixed_query: FixedQuery) -> String {
+ column_eval_var("f", fixed_query.column_index(), fixed_query.rotation().0)
+}
+
+fn advice_eval_var(advice_query: AdviceQuery) -> String {
+ column_eval_var("a", advice_query.column_index(), advice_query.rotation().0)
+}
+
+fn column_eval_var(prefix: &'static str, column_index: usize, rotation: i32) -> String {
+ match rotation.cmp(&0) {
+ Ordering::Less => format!("{prefix}_{column_index}_prev_{}", rotation.abs()),
+ Ordering::Equal => format!("{prefix}_{column_index}"),
+ Ordering::Greater => format!("{prefix}_{column_index}_next_{rotation}"),
+ }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn evaluate(
+ expression: &Expression,
+ constant: &impl Fn(U256) -> T,
+ fixed: &impl Fn(FixedQuery) -> T,
+ advice: &impl Fn(AdviceQuery) -> T,
+ instance: &impl Fn(InstanceQuery) -> T,
+ challenge: &impl Fn(Challenge) -> T,
+ negated: &impl Fn(T) -> T,
+ sum: &impl Fn(T, T) -> T,
+ product: &impl Fn(T, T) -> T,
+ scaled: &impl Fn(T, U256) -> T,
+) -> T
+where
+ F: PrimeField,
+{
+ let evaluate = |expr| {
+ evaluate(
+ expr, constant, fixed, advice, instance, challenge, negated, sum, product, scaled,
+ )
+ };
+ match expression {
+ Expression::Constant(scalar) => constant(field_to_u256(*scalar)),
+ Expression::Selector(_) => unreachable!(),
+ Expression::Fixed(query) => fixed(*query),
+ Expression::Advice(query) => advice(*query),
+ Expression::Instance(query) => instance(*query),
+ Expression::Challenge(value) => challenge(*value),
+ Expression::Negated(value) => negated(evaluate(value)),
+ Expression::Sum(lhs, rhs) => sum(evaluate(lhs), evaluate(rhs)),
+ Expression::Product(lhs, rhs) => product(evaluate(lhs), evaluate(rhs)),
+ Expression::Scaled(value, scalar) => scaled(evaluate(value), field_to_u256(*scalar)),
+ }
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/pcs.rs b/crates/halo2-verifier/src/lib/codegen/pcs.rs
new file mode 100644
index 00000000..5e01a43a
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/pcs.rs
@@ -0,0 +1,104 @@
+use itertools::{chain, izip};
+
+use crate::codegen::util::{ConstraintSystemMeta, Data, EcPoint, Word};
+
+mod bdfg21;
+mod gwc19;
+
+/// KZG batch open schemes in `halo2`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum BatchOpenScheme {
+ /// Batch open scheme in [Plonk] paper.
+ /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverGWC`
+ ///
+ /// [Plonk]: https://eprint.iacr.org/2019/953.pdf
+ Gwc19,
+ /// Batch open scheme in [BDFG21] paper.
+ /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverSHPLONK`
+ ///
+ /// [BDFG21]: https://eprint.iacr.org/2020/081.pdf
+ Bdfg21,
+}
+
+impl BatchOpenScheme {
+ pub(crate) fn static_working_memory_size(
+ &self,
+ meta: &ConstraintSystemMeta,
+ data: &Data,
+ ) -> usize {
+ match self {
+ Self::Bdfg21 => bdfg21::static_working_memory_size(meta, data),
+ Self::Gwc19 => gwc19::static_working_memory_size(meta, data),
+ }
+ }
+
+ pub(crate) fn computations(
+ &self,
+ meta: &ConstraintSystemMeta,
+ data: &Data,
+ ) -> Vec> {
+ match self {
+ Self::Bdfg21 => bdfg21::computations(meta, data),
+ Self::Gwc19 => gwc19::computations(meta, data),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub(crate) struct Query {
+ comm: EcPoint,
+ rot: i32,
+ eval: Word,
+}
+
+impl Query {
+ fn new(comm: EcPoint, rot: i32, eval: Word) -> Self {
+ Self { comm, rot, eval }
+ }
+}
+
+pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec {
+ chain![
+ meta.advice_queries.iter().map(|query| {
+ let comm = data.advice_comms[query.0];
+ let eval = data.advice_evals[query];
+ Query::new(comm, query.1, eval)
+ }),
+ izip!(&data.permutation_z_comms, &data.permutation_z_evals).flat_map(|(&comm, evals)| {
+ [Query::new(comm, 0, evals.0), Query::new(comm, 1, evals.1)]
+ }),
+ izip!(&data.permutation_z_comms, &data.permutation_z_evals)
+ .rev()
+ .skip(1)
+ .map(|(&comm, evals)| Query::new(comm, meta.rotation_last, evals.2)),
+ izip!(
+ &data.lookup_permuted_comms,
+ &data.lookup_z_comms,
+ &data.lookup_evals
+ )
+ .flat_map(|(permuted_comms, &z_comm, evals)| {
+ [
+ Query::new(z_comm, 0, evals.0),
+ Query::new(permuted_comms.0, 0, evals.2),
+ Query::new(permuted_comms.1, 0, evals.4),
+ Query::new(permuted_comms.0, -1, evals.3),
+ Query::new(z_comm, 1, evals.1),
+ ]
+ }),
+ meta.fixed_queries.iter().map(|query| {
+ let comm = data.fixed_comms[query.0];
+ let eval = data.fixed_evals[query];
+ Query::new(comm, query.1, eval)
+ }),
+ meta.permutation_columns.iter().map(|column| {
+ let comm = data.permutation_comms[column];
+ let eval = data.permutation_evals[column];
+ Query::new(comm, 0, eval)
+ }),
+ [
+ Query::new(data.computed_quotient_comm, 0, data.computed_quotient_eval),
+ Query::new(data.random_comm, 0, data.random_eval),
+ ]
+ ]
+ .collect()
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs b/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs
new file mode 100644
index 00000000..b0098625
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs
@@ -0,0 +1,494 @@
+#![allow(clippy::useless_format)]
+
+use std::collections::{BTreeMap, BTreeSet};
+
+use itertools::{chain, izip, Itertools};
+
+use crate::codegen::{
+ pcs::{queries, Query},
+ util::{
+ for_loop, group_backward_adjacent_ec_points, group_backward_adjacent_words,
+ ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word,
+ },
+};
+
+pub(super) fn static_working_memory_size(meta: &ConstraintSystemMeta, data: &Data) -> usize {
+ let (superset, sets) = rotation_sets(&queries(meta, data));
+ let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::();
+ 2 * (1 + num_coeffs) + 6 + 2 * superset.len() + 1 + 3 * sets.len()
+}
+
+pub(super) fn computations(meta: &ConstraintSystemMeta, data: &Data) -> Vec> {
+ let (superset, sets) = rotation_sets(&queries(meta, data));
+ let min_rot = *superset.first().unwrap();
+ let max_rot = *superset.last().unwrap();
+ let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::();
+
+ let w = EcPoint::from(data.w_cptr);
+ let w_prime = EcPoint::from(data.w_cptr + 2);
+
+ let diff_0 = Word::from(Ptr::memory(0x00));
+ let coeffs = sets
+ .iter()
+ .scan(diff_0.ptr() + 1, |state, set| {
+ let ptrs = Word::range(*state).take(set.rots().len()).collect_vec();
+ *state = *state + set.rots().len();
+ Some(ptrs)
+ })
+ .collect_vec();
+
+ let first_batch_invert_end = diff_0.ptr() + 1 + num_coeffs;
+ let second_batch_invert_end = diff_0.ptr() + sets.len();
+ let free_mptr = diff_0.ptr() + 2 * (1 + num_coeffs) + 6;
+
+ let point_mptr = free_mptr;
+ let mu_minus_point_mptr = point_mptr + superset.len();
+ let vanishing_0_mptr = mu_minus_point_mptr + superset.len();
+ let diff_mptr = vanishing_0_mptr + 1;
+ let r_eval_mptr = diff_mptr + sets.len();
+ let sum_mptr = r_eval_mptr + sets.len();
+
+ let point_vars =
+ izip!(&superset, (0..).map(|idx| format!("point_{idx}"))).collect::>();
+ let points = izip!(&superset, Word::range(point_mptr)).collect::>();
+ let mu_minus_points =
+ izip!(&superset, Word::range(mu_minus_point_mptr)).collect::>();
+ let vanishing_0 = Word::from(vanishing_0_mptr);
+ let diffs = Word::range(diff_mptr).take(sets.len()).collect_vec();
+ let r_evals = Word::range(r_eval_mptr).take(sets.len()).collect_vec();
+ let sums = Word::range(sum_mptr).take(sets.len()).collect_vec();
+
+ let point_computations = chain![
+ [
+ "let x := mload(X_MPTR)",
+ "let omega := mload(OMEGA_MPTR)",
+ "let omega_inv := mload(OMEGA_INV_MPTR)",
+ "let x_pow_of_omega := mulmod(x, omega, r)"
+ ]
+ .map(str::to_string),
+ (1..=max_rot).flat_map(|rot| {
+ chain![
+ points
+ .get(&rot)
+ .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())),
+ (rot != max_rot)
+ .then(|| "x_pow_of_omega := mulmod(x_pow_of_omega, omega, r)".to_string())
+ ]
+ }),
+ [
+ format!("mstore({}, x)", points[&0].ptr()),
+ format!("x_pow_of_omega := mulmod(x, omega_inv, r)")
+ ],
+ (min_rot..0).rev().flat_map(|rot| {
+ chain![
+ points
+ .get(&rot)
+ .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())),
+ (rot != min_rot).then(|| {
+ "x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r)".to_string()
+ })
+ ]
+ })
+ ]
+ .collect_vec();
+
+ let vanishing_computations = chain![
+ ["let mu := mload(MU_MPTR)".to_string()],
+ {
+ let mptr = mu_minus_points.first_key_value().unwrap().1.ptr();
+ let mptr_end = mptr + mu_minus_points.len();
+ for_loop(
+ [
+ format!("let mptr := {mptr}"),
+ format!("let mptr_end := {mptr_end}"),
+ format!("let point_mptr := {free_mptr}"),
+ ],
+ "lt(mptr, mptr_end)",
+ [
+ "mptr := add(mptr, 0x20)",
+ "point_mptr := add(point_mptr, 0x20)",
+ ],
+ ["mstore(mptr, addmod(mu, sub(r, mload(point_mptr)), r))"],
+ )
+ },
+ ["let s".to_string()],
+ chain![
+ [format!(
+ "s := {}",
+ mu_minus_points[sets[0].rots().first().unwrap()]
+ )],
+ chain![sets[0].rots().iter().skip(1)]
+ .map(|rot| { format!("s := mulmod(s, {}, r)", mu_minus_points[rot]) }),
+ [format!("mstore({}, s)", vanishing_0.ptr())],
+ ],
+ ["let diff".to_string()],
+ izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, diff)| {
+ chain![
+ [set.diffs()
+ .first()
+ .map(|rot| format!("diff := {}", mu_minus_points[rot]))
+ .unwrap_or_else(|| "diff := 1".to_string())],
+ chain![set.diffs().iter().skip(1)]
+ .map(|rot| { format!("diff := mulmod(diff, {}, r)", mu_minus_points[rot]) }),
+ [format!("mstore({}, diff)", diff.ptr())],
+ (set_idx == 0).then(|| format!("mstore({}, diff)", diff_0.ptr())),
+ ]
+ })
+ ]
+ .collect_vec();
+
+ let coeff_computations = izip!(&sets, &coeffs)
+ .map(|(set, coeffs)| {
+ let coeff_points = set
+ .rots()
+ .iter()
+ .map(|rot| &point_vars[rot])
+ .enumerate()
+ .map(|(i, rot_i)| {
+ set.rots()
+ .iter()
+ .map(|rot| &point_vars[rot])
+ .enumerate()
+ .filter_map(|(j, rot_j)| (i != j).then_some((rot_i, rot_j)))
+ .collect_vec()
+ })
+ .collect_vec();
+ chain![
+ set.rots()
+ .iter()
+ .map(|rot| format!("let {} := {}", &point_vars[rot], points[rot])),
+ ["let coeff".to_string()],
+ izip!(set.rots(), &coeff_points, coeffs).flat_map(
+ |(rot_i, coeff_points, coeff)| chain![
+ [coeff_points
+ .first()
+ .map(|(point_i, point_j)| {
+ format!("coeff := addmod({point_i}, sub(r, {point_j}), r)")
+ })
+ .unwrap_or_else(|| "coeff := 1".to_string())],
+ coeff_points.iter().skip(1).map(|(point_i, point_j)| {
+ let item = format!("addmod({point_i}, sub(r, {point_j}), r)");
+ format!("coeff := mulmod(coeff, {item}, r)")
+ }),
+ [
+ format!("coeff := mulmod(coeff, {}, r)", mu_minus_points[rot_i]),
+ format!("mstore({}, coeff)", coeff.ptr())
+ ],
+ ]
+ )
+ ]
+ .collect_vec()
+ })
+ .collect_vec();
+
+ let normalized_coeff_computations = chain![
+ [
+ format!("success := batch_invert(success, 0, {first_batch_invert_end}, r)"),
+ format!("let diff_0_inv := {diff_0}"),
+ format!("mstore({}, diff_0_inv)", diffs[0].ptr()),
+ ],
+ for_loop(
+ [
+ format!("let mptr := {}", diffs[0].ptr() + 1),
+ format!("let mptr_end := {}", diffs[0].ptr() + sets.len()),
+ ],
+ "lt(mptr, mptr_end)",
+ ["mptr := add(mptr, 0x20)"],
+ ["mstore(mptr, mulmod(mload(mptr), diff_0_inv, r))"],
+ ),
+ ]
+ .collect_vec();
+
+ let r_evals_computations = izip!(0.., &sets, &coeffs, &diffs, &r_evals).map(
+ |(set_idx, set, coeffs, set_coeff, r_eval)| {
+ let is_single_rot_set = set.rots().len() == 1;
+ chain![
+ is_single_rot_set.then(|| format!("let coeff := {}", coeffs[0])),
+ ["let zeta := mload(ZETA_MPTR)", "let r_eval"].map(str::to_string),
+ if is_single_rot_set {
+ let evals = set.evals().iter().map(|evals| evals[0]).collect_vec();
+ let eval_groups = group_backward_adjacent_words(evals.iter().rev().skip(1));
+ chain![
+ evals
+ .last()
+ .map(|eval| format!("r_eval := mulmod(coeff, {eval}, r)")),
+ eval_groups.iter().flat_map(|(loc, evals)| {
+ if evals.len() < 3 {
+ evals
+ .iter()
+ .flat_map(|eval| {
+ let item = format!("mulmod(coeff, {eval}, r)");
+ [
+ format!("r_eval := mulmod(r_eval, zeta, r)"),
+ format!("r_eval := addmod(r_eval, {item}, r)"),
+ ]
+ })
+ .collect_vec()
+ } else {
+ assert_eq!(*loc, Location::Calldata);
+ let item = "mulmod(coeff, calldataload(cptr), r)";
+ for_loop(
+ [
+ format!("let cptr := {}", evals[0].ptr()),
+ format!("let cptr_end := {}", evals[0].ptr() - evals.len()),
+ ],
+ "lt(cptr_end, cptr)",
+ ["cptr := sub(cptr, 0x20)"],
+ [format!(
+ "r_eval := addmod(mulmod(r_eval, zeta, r), {item}, r)"
+ )],
+ )
+ }
+ })
+ ]
+ .collect_vec()
+ } else {
+ chain![set.evals().iter().enumerate().rev()]
+ .flat_map(|(idx, evals)| {
+ chain![
+ izip!(evals, coeffs).map(|(eval, coeff)| {
+ let item = format!("mulmod({coeff}, {eval}, r)");
+ format!("r_eval := addmod(r_eval, {item}, r)")
+ }),
+ (idx != 0).then(|| format!("r_eval := mulmod(r_eval, zeta, r)")),
+ ]
+ })
+ .collect_vec()
+ },
+ (set_idx != 0).then(|| format!("r_eval := mulmod(r_eval, {set_coeff}, r)")),
+ [format!("mstore({}, r_eval)", r_eval.ptr())],
+ ]
+ .collect_vec()
+ },
+ );
+
+ let coeff_sums_computation = izip!(&coeffs, &sums).map(|(coeffs, sum)| {
+ let (coeff_0, rest_coeffs) = coeffs.split_first().unwrap();
+ chain![
+ [format!("let sum := {coeff_0}")],
+ rest_coeffs
+ .iter()
+ .map(|coeff_mptr| format!("sum := addmod(sum, {coeff_mptr}, r)")),
+ [format!("mstore({}, sum)", sum.ptr())],
+ ]
+ .collect_vec()
+ });
+
+ let r_eval_computations = chain![
+ for_loop(
+ [
+ format!("let mptr := 0x00"),
+ format!("let mptr_end := {second_batch_invert_end}"),
+ format!("let sum_mptr := {}", sums[0].ptr()),
+ ],
+ "lt(mptr, mptr_end)",
+ ["mptr := add(mptr, 0x20)", "sum_mptr := add(sum_mptr, 0x20)"],
+ ["mstore(mptr, mload(sum_mptr))"],
+ ),
+ [
+ format!("success := batch_invert(success, 0, {second_batch_invert_end}, r)"),
+ format!(
+ "let r_eval := mulmod(mload({}), {}, r)",
+ second_batch_invert_end - 1,
+ r_evals.last().unwrap()
+ )
+ ],
+ for_loop(
+ [
+ format!("let sum_inv_mptr := {}", second_batch_invert_end - 2),
+ format!("let sum_inv_mptr_end := {second_batch_invert_end}"),
+ format!("let r_eval_mptr := {}", r_evals[r_evals.len() - 2].ptr()),
+ ],
+ "lt(sum_inv_mptr, sum_inv_mptr_end)",
+ [
+ "sum_inv_mptr := sub(sum_inv_mptr, 0x20)",
+ "r_eval_mptr := sub(r_eval_mptr, 0x20)"
+ ],
+ [
+ "r_eval := mulmod(r_eval, mload(NU_MPTR), r)",
+ "r_eval := addmod(r_eval, mulmod(mload(sum_inv_mptr), mload(r_eval_mptr), r), r)"
+ ],
+ ),
+ ["mstore(G1_SCALAR_MPTR, sub(r, r_eval))".to_string()],
+ ]
+ .collect_vec();
+
+ let pairing_input_computations = chain![
+ ["let zeta := mload(ZETA_MPTR)", "let nu := mload(NU_MPTR)"].map(str::to_string),
+ izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, set_coeff)| {
+ let is_first_set = set_idx == 0;
+ let is_last_set = set_idx == sets.len() - 1;
+ let ec_add = &format!("ec_add_{}", if is_first_set { "acc" } else { "tmp" });
+ let ec_mul = &format!("ec_mul_{}", if is_first_set { "acc" } else { "tmp" });
+ let acc_x = Ptr::memory(0x00) + if is_first_set { 0 } else { 4 };
+ let acc_y = acc_x + 1;
+ let comm_groups = group_backward_adjacent_ec_points(set.comms().iter().rev().skip(1));
+
+ chain![
+ set.comms()
+ .last()
+ .map(|comm| {
+ [
+ format!("mstore({acc_x}, {})", comm.x()),
+ format!("mstore({acc_y}, {})", comm.y()),
+ ]
+ })
+ .into_iter()
+ .flatten(),
+ comm_groups.into_iter().flat_map(move |(loc, comms)| {
+ if comms.len() < 3 {
+ comms
+ .iter()
+ .flat_map(|comm| {
+ let (x, y) = (comm.x(), comm.y());
+ [
+ format!("success := {ec_mul}(success, zeta)"),
+ format!("success := {ec_add}(success, {x}, {y})"),
+ ]
+ })
+ .collect_vec()
+ } else {
+ let ptr = comms.first().unwrap().x().ptr();
+ let ptr_end = ptr - 2 * comms.len();
+ let x = Word::from(Ptr::new(loc, "ptr"));
+ let y = Word::from(Ptr::new(loc, "add(ptr, 0x20)"));
+ for_loop(
+ [
+ format!("let ptr := {ptr}"),
+ format!("let ptr_end := {ptr_end}"),
+ ],
+ "lt(ptr_end, ptr)",
+ ["ptr := sub(ptr, 0x40)"],
+ [
+ format!("success := {ec_mul}(success, zeta)"),
+ format!("success := {ec_add}(success, {x}, {y})"),
+ ],
+ )
+ }
+ }),
+ (!is_first_set)
+ .then(|| {
+ let scalar = format!("mulmod(nu, {set_coeff}, r)");
+ chain![
+ [
+ format!("success := ec_mul_tmp(success, {scalar})"),
+ format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"),
+ ],
+ (!is_last_set).then(|| format!("nu := mulmod(nu, mload(NU_MPTR), r)"))
+ ]
+ })
+ .into_iter()
+ .flatten(),
+ ]
+ .collect_vec()
+ }),
+ [
+ format!("mstore(0x80, mload(G1_X_MPTR))"),
+ format!("mstore(0xa0, mload(G1_Y_MPTR))"),
+ format!("success := ec_mul_tmp(success, mload(G1_SCALAR_MPTR))"),
+ format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"),
+ format!("mstore(0x80, {})", w.x()),
+ format!("mstore(0xa0, {})", w.y()),
+ format!("success := ec_mul_tmp(success, sub(r, {vanishing_0}))"),
+ format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"),
+ format!("mstore(0x80, {})", w_prime.x()),
+ format!("mstore(0xa0, {})", w_prime.y()),
+ format!("success := ec_mul_tmp(success, mload(MU_MPTR))"),
+ format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"),
+ format!("mstore(PAIRING_LHS_X_MPTR, mload(0x00))"),
+ format!("mstore(PAIRING_LHS_Y_MPTR, mload(0x20))"),
+ format!("mstore(PAIRING_RHS_X_MPTR, {})", w_prime.x()),
+ format!("mstore(PAIRING_RHS_Y_MPTR, {})", w_prime.y()),
+ ],
+ ]
+ .collect_vec();
+
+ chain![
+ [point_computations, vanishing_computations],
+ coeff_computations,
+ [normalized_coeff_computations],
+ r_evals_computations,
+ coeff_sums_computation,
+ [r_eval_computations, pairing_input_computations],
+ ]
+ .collect_vec()
+}
+
+#[derive(Debug)]
+struct RotationSet {
+ rots: BTreeSet,
+ diffs: BTreeSet,
+ comms: Vec,
+ evals: Vec>,
+}
+
+impl RotationSet {
+ fn rots(&self) -> &BTreeSet {
+ &self.rots
+ }
+
+ fn diffs(&self) -> &BTreeSet {
+ &self.diffs
+ }
+
+ fn comms(&self) -> &[EcPoint] {
+ &self.comms
+ }
+
+ fn evals(&self) -> &[Vec] {
+ &self.evals
+ }
+}
+
+fn rotation_sets(queries: &[Query]) -> (BTreeSet, Vec) {
+ let mut superset = BTreeSet::new();
+ let comm_queries = queries.iter().fold(
+ Vec::<(EcPoint, BTreeMap)>::new(),
+ |mut comm_queries, query| {
+ superset.insert(query.rot);
+ if let Some(pos) = comm_queries
+ .iter()
+ .position(|(comm, _)| comm == &query.comm)
+ {
+ let (_, queries) = &mut comm_queries[pos];
+ assert!(!queries.contains_key(&query.rot));
+ queries.insert(query.rot, query.eval);
+ } else {
+ comm_queries.push((query.comm, BTreeMap::from_iter([(query.rot, query.eval)])));
+ }
+ comm_queries
+ },
+ );
+ let superset = superset;
+ let sets =
+ comm_queries
+ .into_iter()
+ .fold(Vec::::new(), |mut sets, (comm, queries)| {
+ if let Some(pos) = sets
+ .iter()
+ .position(|set| itertools::equal(&set.rots, queries.keys()))
+ {
+ let set = &mut sets[pos];
+ if !set.comms.contains(&comm) {
+ set.comms.push(comm);
+ set.evals.push(queries.into_values().collect_vec());
+ }
+ } else {
+ let diffs = BTreeSet::from_iter(
+ superset
+ .iter()
+ .filter(|rot| !queries.contains_key(rot))
+ .copied(),
+ );
+ let set = RotationSet {
+ rots: BTreeSet::from_iter(queries.keys().copied()),
+ diffs,
+ comms: vec![comm],
+ evals: vec![queries.into_values().collect()],
+ };
+ sets.push(set);
+ }
+ sets
+ });
+ (superset, sets)
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs b/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs
new file mode 100644
index 00000000..a7686a0b
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs
@@ -0,0 +1,300 @@
+#![allow(clippy::useless_format)]
+
+use std::collections::BTreeMap;
+
+use itertools::{chain, izip, Itertools};
+
+use crate::codegen::{
+ pcs::{queries, Query},
+ util::{
+ for_loop, group_backward_adjacent_ec_points, group_backward_adjacent_words,
+ ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word,
+ },
+};
+
+pub(super) fn static_working_memory_size(meta: &ConstraintSystemMeta, _: &Data) -> usize {
+ 0x100 + meta.num_rotations * 0x40
+}
+
+pub(super) fn computations(meta: &ConstraintSystemMeta, data: &Data) -> Vec> {
+ let sets = rotation_sets(&queries(meta, data));
+ let rots = sets.iter().map(|set| set.rot).collect_vec();
+ let (min_rot, max_rot) = rots
+ .iter()
+ .copied()
+ .minmax()
+ .into_option()
+ .unwrap_or_default();
+
+ let ws = EcPoint::range(data.w_cptr).take(sets.len()).collect_vec();
+
+ let point_w_mptr = Ptr::memory(0x100);
+ let point_ws = izip!(rots, EcPoint::range(point_w_mptr)).collect::>();
+
+ let eval_computations = {
+ chain![
+ [
+ "let nu := mload(NU_MPTR)",
+ "let mu := mload(MU_MPTR)",
+ "let eval_acc",
+ "let eval_tmp",
+ ]
+ .map(str::to_string),
+ sets.iter().enumerate().rev().flat_map(|(set_idx, set)| {
+ let is_last_set = set_idx == sets.len() - 1;
+ let eval_acc = &format!("eval_{}", if is_last_set { "acc" } else { "tmp" });
+ let eval_groups = group_backward_adjacent_words(set.evals().iter().rev().skip(1));
+
+ chain![
+ set.evals()
+ .last()
+ .map(|eval| format!("{eval_acc} := {}", eval)),
+ eval_groups.iter().flat_map(|(loc, evals)| {
+ if evals.len() < 3 {
+ evals
+ .iter()
+ .map(|eval| {
+ format!(
+ "{eval_acc} := addmod(mulmod({eval_acc}, nu, r), {eval}, r)"
+ )
+ })
+ .collect_vec()
+ } else {
+ assert_eq!(*loc, Location::Calldata);
+ let eval = "calldataload(cptr)";
+ for_loop(
+ [
+ format!("let cptr := {}", evals[0].ptr()),
+ format!("let cptr_end := {}", evals[0].ptr() - evals.len()),
+ ],
+ "lt(cptr_end, cptr)",
+ ["cptr := sub(cptr, 0x20)"],
+ [format!(
+ "{eval_acc} := addmod(mulmod({eval_acc}, nu, r), {eval}, r)"
+ )],
+ )
+ }
+ }),
+ (!is_last_set)
+ .then_some([
+ "eval_acc := mulmod(eval_acc, mu, r)",
+ "eval_acc := addmod(eval_acc, eval_tmp, r)",
+ ])
+ .into_iter()
+ .flatten()
+ .map(str::to_string),
+ ]
+ .collect_vec()
+ }),
+ ["mstore(G1_SCALAR_MPTR, sub(r, eval_acc))".to_string()],
+ ]
+ .collect_vec()
+ };
+
+ let point_computations = chain![
+ [
+ "let x := mload(X_MPTR)",
+ "let omega := mload(OMEGA_MPTR)",
+ "let omega_inv := mload(OMEGA_INV_MPTR)",
+ "let x_pow_of_omega := mulmod(x, omega, r)"
+ ]
+ .map(str::to_string),
+ (1..=max_rot).flat_map(|rot| {
+ chain![
+ point_ws
+ .get(&rot)
+ .map(|point| format!("mstore({}, x_pow_of_omega)", point.x().ptr())),
+ (rot != max_rot)
+ .then(|| "x_pow_of_omega := mulmod(x_pow_of_omega, omega, r)".to_string())
+ ]
+ }),
+ [
+ format!("mstore({}, x)", point_ws[&0].x().ptr()),
+ format!("x_pow_of_omega := mulmod(x, omega_inv, r)")
+ ],
+ (min_rot..0).rev().flat_map(|rot| {
+ chain![
+ point_ws
+ .get(&rot)
+ .map(|point| format!("mstore({}, x_pow_of_omega)", point.x().ptr())),
+ (rot != min_rot).then(|| {
+ "x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r)".to_string()
+ })
+ ]
+ })
+ ]
+ .collect_vec();
+
+ let point_w_computations = for_loop(
+ [
+ format!("let cptr := {}", data.w_cptr),
+ format!("let mptr := {point_w_mptr}"),
+ format!("let mptr_end := {}", point_w_mptr + 2 * sets.len()),
+ ],
+ "lt(mptr, mptr_end)".to_string(),
+ ["mptr := add(mptr, 0x40)", "cptr := add(cptr, 0x40)"].map(str::to_string),
+ [
+ "mstore(0x00, calldataload(cptr))",
+ "mstore(0x20, calldataload(add(cptr, 0x20)))",
+ "success := ec_mul_acc(success, mload(mptr))",
+ "mstore(mptr, mload(0x00))",
+ "mstore(add(mptr, 0x20), mload(0x20))",
+ ]
+ .map(str::to_string),
+ );
+
+ let pairing_lhs_computations = chain![
+ ["let nu := mload(NU_MPTR)", "let mu := mload(MU_MPTR)"].map(str::to_string),
+ sets.iter().enumerate().rev().flat_map(|(set_idx, set)| {
+ let is_last_set = set_idx == sets.len() - 1;
+ let ec_add = &format!("ec_add_{}", if is_last_set { "acc" } else { "tmp" });
+ let ec_mul = &format!("ec_mul_{}", if is_last_set { "acc" } else { "tmp" });
+ let acc_x = Ptr::memory(0x00) + if is_last_set { 0 } else { 4 };
+ let acc_y = acc_x + 1;
+ let point_w = &point_ws[&set.rot];
+ let comm_groups = group_backward_adjacent_ec_points(set.comms().iter().rev().skip(1));
+
+ chain![
+ set.comms()
+ .last()
+ .map(|comm| {
+ [
+ format!("mstore({acc_x}, {})", comm.x()),
+ format!("mstore({acc_y}, {})", comm.y()),
+ ]
+ })
+ .into_iter()
+ .flatten(),
+ comm_groups.into_iter().flat_map(move |(loc, comms)| {
+ if comms.len() < 3 {
+ comms
+ .iter()
+ .flat_map(|comm| {
+ let (x, y) = (comm.x(), comm.y());
+ [
+ format!("success := {ec_mul}(success, nu)"),
+ format!("success := {ec_add}(success, {x}, {y})"),
+ ]
+ })
+ .collect_vec()
+ } else {
+ let ptr = comms.first().unwrap().x().ptr();
+ let ptr_end = ptr - 2 * comms.len();
+ let x = Word::from(Ptr::new(loc, "ptr"));
+ let y = Word::from(Ptr::new(loc, "add(ptr, 0x20)"));
+ for_loop(
+ [
+ format!("let ptr := {ptr}"),
+ format!("let ptr_end := {ptr_end}"),
+ ],
+ "lt(ptr_end, ptr)",
+ ["ptr := sub(ptr, 0x40)".to_string()],
+ [
+ format!("success := {ec_mul}(success, nu)"),
+ format!("success := {ec_add}(success, {x}, {y})"),
+ ],
+ )
+ }
+ }),
+ [format!(
+ "success := {ec_add}(success, {}, {})",
+ point_w.x(),
+ point_w.y()
+ )],
+ (!is_last_set)
+ .then_some([
+ "success := ec_mul_acc(success, mu)",
+ "success := ec_add_acc(success, mload(0x80), mload(0xa0))",
+ ])
+ .into_iter()
+ .flatten()
+ .map(str::to_string),
+ ]
+ .collect_vec()
+ }),
+ [
+ "mstore(0x80, mload(G1_X_MPTR))",
+ "mstore(0xa0, mload(G1_Y_MPTR))",
+ "success := ec_mul_tmp(success, mload(G1_SCALAR_MPTR))",
+ "success := ec_add_acc(success, mload(0x80), mload(0xa0))",
+ "mstore(PAIRING_LHS_X_MPTR, mload(0x00))",
+ "mstore(PAIRING_LHS_Y_MPTR, mload(0x20))",
+ ]
+ .map(str::to_string),
+ ]
+ .collect_vec();
+
+ let pairing_rhs_computations = chain![
+ [
+ format!("let mu := mload(MU_MPTR)"),
+ format!("mstore(0x00, {})", ws.last().unwrap().x()),
+ format!("mstore(0x20, {})", ws.last().unwrap().y()),
+ ],
+ ws.iter()
+ .nth_back(1)
+ .map(|w_second_last| {
+ let x = "calldataload(cptr)";
+ let y = "calldataload(add(cptr, 0x20))";
+ for_loop(
+ [
+ format!("let cptr := {}", w_second_last.x().ptr()),
+ format!("let cptr_end := {}", ws[0].x().ptr() - 1),
+ ],
+ "lt(cptr_end, cptr)",
+ ["cptr := sub(cptr, 0x40)"],
+ [
+ format!("success := ec_mul_acc(success, mu)"),
+ format!("success := ec_add_acc(success, {x}, {y})"),
+ ],
+ )
+ })
+ .into_iter()
+ .flatten(),
+ [
+ format!("mstore(PAIRING_RHS_X_MPTR, mload(0x00))"),
+ format!("mstore(PAIRING_RHS_Y_MPTR, mload(0x20))"),
+ ],
+ ]
+ .collect_vec();
+
+ vec![
+ eval_computations,
+ point_computations,
+ point_w_computations,
+ pairing_lhs_computations,
+ pairing_rhs_computations,
+ ]
+}
+
+#[derive(Debug)]
+struct RotationSet {
+ rot: i32,
+ comms: Vec,
+ evals: Vec,
+}
+
+impl RotationSet {
+ fn comms(&self) -> &[EcPoint] {
+ &self.comms
+ }
+
+ fn evals(&self) -> &[Word] {
+ &self.evals
+ }
+}
+
+fn rotation_sets(queries: &[Query]) -> Vec {
+ queries.iter().fold(Vec::new(), |mut sets, query| {
+ if let Some(pos) = sets.iter().position(|set| set.rot == query.rot) {
+ sets[pos].comms.push(query.comm);
+ sets[pos].evals.push(query.eval);
+ } else {
+ sets.push(RotationSet {
+ rot: query.rot,
+ comms: vec![query.comm],
+ evals: vec![query.eval],
+ });
+ }
+ sets
+ })
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/template.rs b/crates/halo2-verifier/src/lib/codegen/template.rs
new file mode 100644
index 00000000..91966e54
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/template.rs
@@ -0,0 +1,86 @@
+use std::fmt;
+
+use askama::{Error, Template};
+use ruint::aliases::U256;
+
+use crate::codegen::{
+ pcs::BatchOpenScheme::{self, Bdfg21, Gwc19},
+ util::Ptr,
+};
+
+#[derive(Template)]
+#[template(path = "Halo2VerifyingKey.sol")]
+pub(crate) struct Halo2VerifyingKey {
+ pub(crate) constants: Vec<(&'static str, U256)>,
+ pub(crate) fixed_comms: Vec<(U256, U256)>,
+ pub(crate) permutation_comms: Vec<(U256, U256)>,
+}
+
+impl Halo2VerifyingKey {
+ pub(crate) fn len(&self) -> usize {
+ (self.constants.len() * 0x20)
+ + (self.fixed_comms.len() + self.permutation_comms.len()) * 0x40
+ }
+}
+
+#[derive(Template)]
+#[template(path = "Halo2Verifier.sol")]
+pub(crate) struct Halo2Verifier {
+ pub(crate) scheme: BatchOpenScheme,
+ pub(crate) embedded_vk: Option,
+ pub(crate) vk_len: usize,
+ pub(crate) proof_len: usize,
+ pub(crate) vk_mptr: Ptr,
+ pub(crate) challenge_mptr: Ptr,
+ pub(crate) theta_mptr: Ptr,
+ pub(crate) proof_cptr: Ptr,
+ pub(crate) quotient_comm_cptr: Ptr,
+ pub(crate) num_neg_lagranges: usize,
+ pub(crate) num_advices: Vec,
+ pub(crate) num_challenges: Vec,
+ pub(crate) num_rotations: usize,
+ pub(crate) num_evals: usize,
+ pub(crate) num_quotients: usize,
+ pub(crate) quotient_eval_numer_computations: Vec>,
+ pub(crate) pcs_computations: Vec>,
+}
+
+impl Halo2VerifyingKey {
+ pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> {
+ self.render_into(writer).map_err(|err| match err {
+ Error::Fmt(err) => err,
+ _ => unreachable!(),
+ })
+ }
+}
+
+impl Halo2Verifier {
+ pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> {
+ self.render_into(writer).map_err(|err| match err {
+ Error::Fmt(err) => err,
+ _ => unreachable!(),
+ })
+ }
+}
+
+mod filters {
+ use std::fmt::LowerHex;
+
+ pub fn hex(value: impl LowerHex) -> ::askama::Result {
+ let value = format!("{value:x}");
+ Ok(if value.len() % 2 == 1 {
+ format!("0x0{value}")
+ } else {
+ format!("0x{value}")
+ })
+ }
+
+ pub fn hex_padded(value: impl LowerHex, pad: usize) -> ::askama::Result {
+ let string = format!("0x{value:0pad$x}");
+ if string == "0x0" {
+ Ok(format!("0x{}", "0".repeat(pad)))
+ } else {
+ Ok(string)
+ }
+ }
+}
diff --git a/crates/halo2-verifier/src/lib/codegen/util.rs b/crates/halo2-verifier/src/lib/codegen/util.rs
new file mode 100644
index 00000000..83345a75
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/codegen/util.rs
@@ -0,0 +1,660 @@
+use std::{
+ borrow::Borrow,
+ collections::HashMap,
+ fmt::{self, Display, Formatter},
+ ops::{Add, Sub},
+};
+
+use halo2_proofs::{
+ halo2curves::{bn256, bn256::Fq, ff::PrimeField, CurveAffine},
+ plonk::{Any, Column, ConstraintSystem},
+};
+use itertools::{chain, izip, Itertools};
+use ruint::aliases::U256;
+use shielder_rust_sdk::conversion::field_to_u256;
+
+use crate::codegen::{
+ template::Halo2VerifyingKey,
+ BatchOpenScheme::{self, Bdfg21, Gwc19},
+};
+
+#[derive(Debug)]
+pub(crate) struct ConstraintSystemMeta {
+ pub(crate) num_fixeds: usize,
+ pub(crate) permutation_columns: Vec>,
+ pub(crate) permutation_chunk_len: usize,
+ pub(crate) num_lookup_permuteds: usize,
+ pub(crate) num_permutation_zs: usize,
+ pub(crate) num_lookup_zs: usize,
+ pub(crate) num_quotients: usize,
+ pub(crate) advice_queries: Vec<(usize, i32)>,
+ pub(crate) fixed_queries: Vec<(usize, i32)>,
+ pub(crate) num_rotations: usize,
+ pub(crate) num_evals: usize,
+ pub(crate) num_user_advices: Vec,
+ pub(crate) num_user_challenges: Vec,
+ pub(crate) advice_indices: Vec,
+ pub(crate) challenge_indices: Vec,
+ pub(crate) rotation_last: i32,
+}
+
+impl ConstraintSystemMeta {
+ pub(crate) fn new(cs: &ConstraintSystem) -> Self {
+ let num_fixeds = cs.num_fixed_columns();
+ let permutation_columns = cs.permutation().get_columns();
+ let permutation_chunk_len = cs.degree() - 2;
+ let num_lookup_permuteds = 2 * cs.lookups().len();
+ let num_permutation_zs = cs
+ .permutation()
+ .get_columns()
+ .chunks(cs.degree() - 2)
+ .count();
+ let num_lookup_zs = cs.lookups().len();
+ let num_quotients = cs.degree() - 1;
+ let advice_queries = cs
+ .advice_queries()
+ .iter()
+ .map(|(column, rotation)| (column.index(), rotation.0))
+ .collect_vec();
+ let fixed_queries = cs
+ .fixed_queries()
+ .iter()
+ .map(|(column, rotation)| (column.index(), rotation.0))
+ .collect_vec();
+ let num_evals = advice_queries.len()
+ + fixed_queries.len()
+ + 1
+ + cs.permutation().get_columns().len()
+ + (3 * num_permutation_zs - 1)
+ + 5 * cs.lookups().len();
+ let num_phase = *cs.advice_column_phase().iter().max().unwrap_or(&0) as usize + 1;
+ // Indices of advice and challenge are not same as their position in calldata/memory,
+ // because we support multiple phases, we need to remap them and find their actual indices.
+ let remapping = |phase: Vec| {
+ let nums = phase.iter().fold(vec![0; num_phase], |mut nums, phase| {
+ nums[*phase as usize] += 1;
+ nums
+ });
+ let offsets = nums
+ .iter()
+ .take(num_phase - 1)
+ .fold(vec![0], |mut offsets, n| {
+ offsets.push(offsets.last().unwrap() + n);
+ offsets
+ });
+ let index = phase
+ .iter()
+ .scan(offsets, |state, phase| {
+ let index = state[*phase as usize];
+ state[*phase as usize] += 1;
+ Some(index)
+ })
+ .collect::>();
+ (nums, index)
+ };
+ let (num_user_advices, advice_indices) = remapping(cs.advice_column_phase());
+ let (num_user_challenges, challenge_indices) = remapping(cs.challenge_phase());
+ let rotation_last = -(cs.blinding_factors() as i32 + 1);
+ let num_rotations = chain![
+ advice_queries.iter().map(|query| query.1),
+ fixed_queries.iter().map(|query| query.1),
+ (num_permutation_zs > 0)
+ .then_some([0, 1])
+ .into_iter()
+ .flatten(),
+ (num_permutation_zs > 1).then_some(rotation_last),
+ (num_lookup_zs > 0)
+ .then_some([-1, 0, 1])
+ .into_iter()
+ .flatten(),
+ ]
+ .unique()
+ .count();
+ Self {
+ num_fixeds,
+ permutation_columns,
+ permutation_chunk_len,
+ num_lookup_permuteds,
+ num_permutation_zs,
+ num_lookup_zs,
+ num_quotients,
+ advice_queries,
+ fixed_queries,
+ num_evals,
+ num_rotations,
+ num_user_advices,
+ num_user_challenges,
+ advice_indices,
+ challenge_indices,
+ rotation_last,
+ }
+ }
+
+ pub(crate) fn num_advices(&self) -> Vec {
+ chain![
+ self.num_user_advices.iter().cloned(),
+ (self.num_lookup_permuteds != 0).then_some(self.num_lookup_permuteds), // lookup permuted
+ [
+ self.num_permutation_zs + self.num_lookup_zs + 1, // permutation and lookup grand products, random
+ self.num_quotients, // quotients
+ ],
+ ]
+ .collect()
+ }
+
+ pub(crate) fn num_challenges(&self) -> Vec {
+ let mut num_challenges = self.num_user_challenges.clone();
+ // If there is no lookup used, merge also beta and gamma into the last user phase, to avoid
+ // squeezing challenge from nothing.
+ // Otherwise, merge theta into last user phase since they are originally adjacent.
+ if self.num_lookup_permuteds == 0 {
+ *num_challenges.last_mut().unwrap() += 3; // theta, beta, gamma
+ num_challenges.extend([
+ 1, // y
+ 1, // x
+ ]);
+ } else {
+ *num_challenges.last_mut().unwrap() += 1; // theta
+ num_challenges.extend([
+ 2, // beta, gamma
+ 1, // y
+ 1, // x
+ ]);
+ }
+ num_challenges
+ }
+
+ pub(crate) fn num_permutations(&self) -> usize {
+ self.permutation_columns.len()
+ }
+
+ pub(crate) fn num_lookups(&self) -> usize {
+ self.num_lookup_zs
+ }
+
+ pub(crate) fn proof_len(&self, scheme: BatchOpenScheme) -> usize {
+ self.num_advices().iter().sum::() * 0x40
+ + self.num_evals * 0x20
+ + self.batch_open_proof_len(scheme)
+ }
+
+ pub(crate) fn batch_open_proof_len(&self, scheme: BatchOpenScheme) -> usize {
+ (match scheme {
+ Bdfg21 => 2,
+ Gwc19 => self.num_rotations,
+ }) * 0x40
+ }
+}
+
+#[derive(Debug)]
+pub(crate) struct Data {
+ pub(crate) challenge_mptr: Ptr,
+ pub(crate) theta_mptr: Ptr,
+
+ pub(crate) quotient_comm_cptr: Ptr,
+ pub(crate) w_cptr: Ptr,
+
+ pub(crate) fixed_comms: Vec,
+ pub(crate) permutation_comms: HashMap, EcPoint>,
+ pub(crate) advice_comms: Vec,
+ pub(crate) lookup_permuted_comms: Vec<(EcPoint, EcPoint)>,
+ pub(crate) permutation_z_comms: Vec,
+ pub(crate) lookup_z_comms: Vec,
+ pub(crate) random_comm: EcPoint,
+
+ pub(crate) challenges: Vec,
+
+ pub(crate) instance_eval: Word,
+ pub(crate) advice_evals: HashMap<(usize, i32), Word>,
+ pub(crate) fixed_evals: HashMap<(usize, i32), Word>,
+ pub(crate) random_eval: Word,
+ pub(crate) permutation_evals: HashMap, Word>,
+ pub(crate) permutation_z_evals: Vec<(Word, Word, Word)>,
+ pub(crate) lookup_evals: Vec<(Word, Word, Word, Word, Word)>,
+
+ pub(crate) computed_quotient_comm: EcPoint,
+ pub(crate) computed_quotient_eval: Word,
+}
+
+impl Data {
+ pub(crate) fn new(
+ meta: &ConstraintSystemMeta,
+ vk: &Halo2VerifyingKey,
+ vk_mptr: Ptr,
+ proof_cptr: Ptr,
+ ) -> Self {
+ let fixed_comm_mptr = vk_mptr + vk.constants.len();
+ let permutation_comm_mptr = fixed_comm_mptr + 2 * vk.fixed_comms.len();
+ let challenge_mptr = permutation_comm_mptr + 2 * vk.permutation_comms.len();
+ let theta_mptr = challenge_mptr + meta.challenge_indices.len();
+
+ let advice_comm_start = proof_cptr;
+ let lookup_permuted_comm_start = advice_comm_start + 2 * meta.advice_indices.len();
+ let permutation_z_comm_start = lookup_permuted_comm_start + 2 * meta.num_lookup_permuteds;
+ let lookup_z_comm_start = permutation_z_comm_start + 2 * meta.num_permutation_zs;
+ let random_comm_start = lookup_z_comm_start + 2 * meta.num_lookup_zs;
+ let quotient_comm_start = random_comm_start + 2;
+
+ let eval_cptr = quotient_comm_start + 2 * meta.num_quotients;
+ let advice_eval_cptr = eval_cptr;
+ let fixed_eval_cptr = advice_eval_cptr + meta.advice_queries.len();
+ let random_eval_cptr = fixed_eval_cptr + meta.fixed_queries.len();
+ let permutation_eval_cptr = random_eval_cptr + 1;
+ let permutation_z_eval_cptr = permutation_eval_cptr + meta.num_permutations();
+ let lookup_eval_cptr = permutation_z_eval_cptr + 3 * meta.num_permutation_zs - 1;
+ let w_cptr = lookup_eval_cptr + 5 * meta.num_lookups();
+
+ let fixed_comms = EcPoint::range(fixed_comm_mptr)
+ .take(meta.num_fixeds)
+ .collect();
+ let permutation_comms = izip!(
+ meta.permutation_columns.iter().cloned(),
+ EcPoint::range(permutation_comm_mptr)
+ )
+ .collect();
+ let advice_comms = meta
+ .advice_indices
+ .iter()
+ .map(|idx| advice_comm_start + 2 * idx)
+ .map_into()
+ .collect();
+ let lookup_permuted_comms = EcPoint::range(lookup_permuted_comm_start)
+ .take(meta.num_lookup_permuteds)
+ .tuples()
+ .collect();
+ let permutation_z_comms = EcPoint::range(permutation_z_comm_start)
+ .take(meta.num_permutation_zs)
+ .collect();
+ let lookup_z_comms = EcPoint::range(lookup_z_comm_start)
+ .take(meta.num_lookup_zs)
+ .collect();
+ let random_comm = random_comm_start.into();
+ let computed_quotient_comm = EcPoint::new(
+ Ptr::memory("QUOTIENT_X_MPTR"),
+ Ptr::memory("QUOTIENT_Y_MPTR"),
+ );
+
+ let challenges = meta
+ .challenge_indices
+ .iter()
+ .map(|idx| challenge_mptr + *idx)
+ .map_into()
+ .collect_vec();
+ let instance_eval = Ptr::memory("INSTANCE_EVAL_MPTR").into();
+ let advice_evals = izip!(
+ meta.advice_queries.iter().cloned(),
+ Word::range(advice_eval_cptr)
+ )
+ .collect();
+ let fixed_evals = izip!(
+ meta.fixed_queries.iter().cloned(),
+ Word::range(fixed_eval_cptr)
+ )
+ .collect();
+ let random_eval = random_eval_cptr.into();
+ let permutation_evals = izip!(
+ meta.permutation_columns.iter().cloned(),
+ Word::range(permutation_eval_cptr)
+ )
+ .collect();
+ let permutation_z_evals = Word::range(permutation_z_eval_cptr)
+ .take(3 * meta.num_permutation_zs)
+ .tuples()
+ .collect_vec();
+ let lookup_evals = Word::range(lookup_eval_cptr)
+ .take(5 * meta.num_lookup_zs)
+ .tuples()
+ .collect_vec();
+ let computed_quotient_eval = Ptr::memory("QUOTIENT_EVAL_MPTR").into();
+
+ Self {
+ challenge_mptr,
+ theta_mptr,
+ quotient_comm_cptr: quotient_comm_start,
+ w_cptr,
+
+ fixed_comms,
+ permutation_comms,
+ advice_comms,
+ lookup_permuted_comms,
+ permutation_z_comms,
+ lookup_z_comms,
+ random_comm,
+ computed_quotient_comm,
+
+ challenges,
+
+ instance_eval,
+ advice_evals,
+ fixed_evals,
+ permutation_evals,
+ permutation_z_evals,
+ lookup_evals,
+ random_eval,
+ computed_quotient_eval,
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) enum Location {
+ Calldata,
+ Memory,
+}
+
+impl Location {
+ fn opcode(&self) -> &'static str {
+ match self {
+ Location::Calldata => "calldataload",
+ Location::Memory => "mload",
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) enum Value {
+ Integer(usize),
+ Identifier(&'static str),
+}
+
+impl Value {
+ pub(crate) fn is_integer(&self) -> bool {
+ match self {
+ Value::Integer(_) => true,
+ Value::Identifier(_) => false,
+ }
+ }
+
+ pub(crate) fn as_usize(&self) -> usize {
+ match self {
+ Value::Integer(int) => *int,
+ Value::Identifier(_) => unreachable!(),
+ }
+ }
+}
+
+impl Default for Value {
+ fn default() -> Self {
+ Self::Integer(0)
+ }
+}
+
+impl From<&'static str> for Value {
+ fn from(ident: &'static str) -> Self {
+ Value::Identifier(ident)
+ }
+}
+
+impl From for Value {
+ fn from(int: usize) -> Self {
+ Value::Integer(int)
+ }
+}
+
+impl Display for Value {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ Value::Integer(int) => {
+ let hex = format!("{int:x}");
+ if hex.len() % 2 == 1 {
+ write!(f, "0x0{hex}")
+ } else {
+ write!(f, "0x{hex}")
+ }
+ }
+ Value::Identifier(ident) => {
+ write!(f, "{ident}")
+ }
+ }
+ }
+}
+
+impl Add for Value {
+ type Output = Value;
+
+ fn add(self, rhs: usize) -> Self::Output {
+ (self.as_usize() + rhs * 0x20).into()
+ }
+}
+
+impl Sub for Value {
+ type Output = Value;
+
+ fn sub(self, rhs: usize) -> Self::Output {
+ (self.as_usize() - rhs * 0x20).into()
+ }
+}
+
+/// `Ptr` points to a EVM word at either calldata or memory.
+///
+/// When adding or subtracting it by 1, its value moves by 32 and points to next/previous EVM word.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) struct Ptr {
+ loc: Location,
+ value: Value,
+}
+
+impl Ptr {
+ pub(crate) fn new(loc: Location, value: impl Into) -> Self {
+ Self {
+ loc,
+ value: value.into(),
+ }
+ }
+
+ pub(crate) fn memory(value: impl Into) -> Self {
+ Self::new(Location::Memory, value.into())
+ }
+
+ pub(crate) fn calldata(value: impl Into) -> Self {
+ Self::new(Location::Calldata, value.into())
+ }
+
+ pub(crate) fn loc(&self) -> Location {
+ self.loc
+ }
+
+ pub(crate) fn value(&self) -> Value {
+ self.value
+ }
+}
+
+impl Display for Ptr {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.value)
+ }
+}
+
+impl Add for Ptr {
+ type Output = Ptr;
+
+ fn add(mut self, rhs: usize) -> Self::Output {
+ self.value = self.value + rhs;
+ self
+ }
+}
+
+impl Sub for Ptr {
+ type Output = Ptr;
+
+ fn sub(mut self, rhs: usize) -> Self::Output {
+ self.value = self.value - rhs;
+ self
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) struct Word(Ptr);
+
+impl Word {
+ pub(crate) fn range(word: impl Into) -> impl Iterator- {
+ let ptr = word.into().ptr();
+ (0..).map(move |idx| ptr + idx).map_into()
+ }
+
+ pub(crate) fn ptr(&self) -> Ptr {
+ self.0
+ }
+
+ pub(crate) fn loc(&self) -> Location {
+ self.0.loc()
+ }
+}
+
+impl Display for Word {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ write!(f, "{}({})", self.0.loc.opcode(), self.0.value)
+ }
+}
+
+impl From for Word {
+ fn from(ptr: Ptr) -> Self {
+ Self(ptr)
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) struct EcPoint {
+ x: Word,
+ y: Word,
+}
+
+impl EcPoint {
+ pub(crate) fn new(x: impl Into, y: impl Into) -> Self {
+ Self {
+ x: x.into(),
+ y: y.into(),
+ }
+ }
+
+ pub(crate) fn range(ec_point: impl Into) -> impl Iterator
- {
+ let ptr = ec_point.into().x.ptr();
+ (0..).map(move |idx| ptr + 2 * idx).map_into()
+ }
+
+ pub(crate) fn loc(&self) -> Location {
+ self.x.ptr().loc()
+ }
+
+ pub(crate) fn x(&self) -> Word {
+ self.x
+ }
+
+ pub(crate) fn y(&self) -> Word {
+ self.y
+ }
+}
+
+impl From for EcPoint {
+ fn from(ptr: Ptr) -> Self {
+ Self::new(ptr, ptr + 1)
+ }
+}
+
+/// Add indention to given lines by `4 * N` spaces.
+pub(crate) fn indent(
+ lines: impl IntoIterator
- >,
+) -> Vec {
+ lines
+ .into_iter()
+ .map(|line| format!("{}{}", " ".repeat(N * 4), line.into()))
+ .collect()
+}
+
+/// Create a code block for given lines with indention.
+///
+/// If `PACKED` is true, single line code block will be packed into single line.
+pub(crate) fn code_block(
+ lines: impl IntoIterator
- >,
+) -> Vec {
+ let lines = lines.into_iter().map_into().collect_vec();
+ let bracket_indent = " ".repeat((N - 1) * 4);
+ match lines.len() {
+ 0 => vec![format!("{bracket_indent}{{}}")],
+ 1 if PACKED => vec![format!("{bracket_indent}{{ {} }}", lines[0])],
+ _ => chain![
+ [format!("{bracket_indent}{{")],
+ indent::(lines),
+ [format!("{bracket_indent}}}")],
+ ]
+ .collect(),
+ }
+}
+
+/// Create a for loop with proper indention.
+pub(crate) fn for_loop(
+ initialization: impl IntoIterator
- >,
+ condition: impl Into,
+ advancement: impl IntoIterator
- >,
+ body: impl IntoIterator
- >,
+) -> Vec {
+ chain![
+ ["for".to_string()],
+ code_block::<2, true>(initialization),
+ indent::<1>([condition.into()]),
+ code_block::<2, true>(advancement),
+ code_block::<1, false>(body),
+ ]
+ .collect()
+}
+
+pub(crate) fn group_backward_adjacent_words<'a>(
+ words: impl IntoIterator
- ,
+) -> Vec<(Location, Vec<&'a Word>)> {
+ words.into_iter().fold(Vec::new(), |mut word_groups, word| {
+ if let Some(last_group) = word_groups.last_mut() {
+ let last_word = **last_group.1.last().unwrap();
+ if last_group.0 == word.loc()
+ && last_word.ptr().value().is_integer()
+ && last_word.ptr() - 1 == word.ptr()
+ {
+ last_group.1.push(word)
+ } else {
+ word_groups.push((word.loc(), vec![word]))
+ }
+ word_groups
+ } else {
+ vec![(word.loc(), vec![word])]
+ }
+ })
+}
+
+pub(crate) fn group_backward_adjacent_ec_points<'a>(
+ ec_point: impl IntoIterator
- ,
+) -> Vec<(Location, Vec<&'a EcPoint>)> {
+ ec_point
+ .into_iter()
+ .fold(Vec::new(), |mut ec_point_groups, ec_point| {
+ if let Some(last_group) = ec_point_groups.last_mut() {
+ let last_ec_point = **last_group.1.last().unwrap();
+ if last_group.0 == ec_point.loc()
+ && last_ec_point.x().ptr().value().is_integer()
+ && last_ec_point.x().ptr() - 2 == ec_point.x().ptr()
+ {
+ last_group.1.push(ec_point)
+ } else {
+ ec_point_groups.push((ec_point.loc(), vec![ec_point]))
+ }
+ ec_point_groups
+ } else {
+ vec![(ec_point.loc(), vec![ec_point])]
+ }
+ })
+}
+
+pub(crate) fn g1_to_u256s(ec_point: impl Borrow) -> [U256; 2] {
+ let coords = ec_point.borrow().coordinates().unwrap();
+ [coords.x(), coords.y()].map(field_to_u256::)
+}
+
+pub(crate) fn g2_to_u256s(ec_point: impl Borrow) -> [U256; 4] {
+ let coords = ec_point.borrow().coordinates().unwrap();
+ let x = coords.x().to_repr();
+ let y = coords.y().to_repr();
+ [
+ U256::try_from_le_slice(&x.as_ref()[0x20..]).unwrap(),
+ U256::try_from_le_slice(&x.as_ref()[..0x20]).unwrap(),
+ U256::try_from_le_slice(&y.as_ref()[0x20..]).unwrap(),
+ U256::try_from_le_slice(&y.as_ref()[..0x20]).unwrap(),
+ ]
+}
diff --git a/crates/halo2-verifier/src/lib/lib.rs b/crates/halo2-verifier/src/lib/lib.rs
new file mode 100644
index 00000000..bf362ce3
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/lib.rs
@@ -0,0 +1,12 @@
+//! Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254.
+//!
+//! [`halo2`]: http://github.com/privacy-scaling-explorations/halo2
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+mod codegen;
+pub mod verifier_contract;
+
+pub use codegen::{AccumulatorEncoding, BatchOpenScheme, SolidityGenerator};
diff --git a/crates/halo2-verifier/src/lib/verifier_contract.rs b/crates/halo2-verifier/src/lib/verifier_contract.rs
new file mode 100644
index 00000000..fb14d89a
--- /dev/null
+++ b/crates/halo2-verifier/src/lib/verifier_contract.rs
@@ -0,0 +1,23 @@
+#![allow(missing_docs)]
+use alloy_primitives::Address;
+use alloy_sol_types::{private::Bytes, sol, SolCall};
+use halo2_proofs::halo2curves::bn256::Fr;
+use shielder_rust_sdk::conversion::field_to_u256;
+
+sol! {
+ function verifyProof(
+ address vk,
+ bytes calldata proof,
+ uint256[] calldata instances
+ ) public returns (bool);
+}
+
+/// Encode proof into calldata to invoke `Halo2Verifier.verifyProof`.
+pub fn encode_calldata(vk: Address, proof: &[u8], instances: &[Fr]) -> Vec {
+ verifyProofCall {
+ vk,
+ proof: Bytes::from(proof.to_vec()),
+ instances: instances.iter().map(field_to_u256::).collect(),
+ }
+ .abi_encode()
+}
diff --git a/crates/halo2-verifier/templates/Halo2Verifier.sol b/crates/halo2-verifier/templates/Halo2Verifier.sol
new file mode 100644
index 00000000..96568abb
--- /dev/null
+++ b/crates/halo2-verifier/templates/Halo2Verifier.sol
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity 0.8.26;
+
+/* @dev: linter does not understand inline assembly */
+/* solhint-disable no-unused-vars */
+contract Halo2Verifier {
+ uint256 internal constant PROOF_LEN_CPTR = {{ proof_cptr - 1 }};
+ uint256 internal constant PROOF_CPTR = {{ proof_cptr }};
+ uint256 internal constant NUM_INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) }};
+ uint256 internal constant INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) + 1 }};
+
+ uint256 internal constant FIRST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr }};
+ uint256 internal constant LAST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr + 2 * (num_quotients - 1) }};
+
+ uint256 internal constant VK_MPTR = {{ vk_mptr }};
+ uint256 internal constant VK_DIGEST_MPTR = {{ vk_mptr }};
+ uint256 internal constant NUM_INSTANCES_MPTR = {{ vk_mptr + 1 }};
+ uint256 internal constant K_MPTR = {{ vk_mptr + 2 }};
+ uint256 internal constant N_INV_MPTR = {{ vk_mptr + 3 }};
+ uint256 internal constant OMEGA_MPTR = {{ vk_mptr + 4 }};
+ uint256 internal constant OMEGA_INV_MPTR = {{ vk_mptr + 5 }};
+ uint256 internal constant OMEGA_INV_TO_L_MPTR = {{ vk_mptr + 6 }};
+ uint256 internal constant HAS_ACCUMULATOR_MPTR = {{ vk_mptr + 7 }};
+ uint256 internal constant ACC_OFFSET_MPTR = {{ vk_mptr + 8 }};
+ uint256 internal constant NUM_ACC_LIMBS_MPTR = {{ vk_mptr + 9 }};
+ uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = {{ vk_mptr + 10 }};
+ uint256 internal constant G1_X_MPTR = {{ vk_mptr + 11 }};
+ uint256 internal constant G1_Y_MPTR = {{ vk_mptr + 12 }};
+ uint256 internal constant G2_X_1_MPTR = {{ vk_mptr + 13 }};
+ uint256 internal constant G2_X_2_MPTR = {{ vk_mptr + 14 }};
+ uint256 internal constant G2_Y_1_MPTR = {{ vk_mptr + 15 }};
+ uint256 internal constant G2_Y_2_MPTR = {{ vk_mptr + 16 }};
+ uint256 internal constant NEG_S_G2_X_1_MPTR = {{ vk_mptr + 17 }};
+ uint256 internal constant NEG_S_G2_X_2_MPTR = {{ vk_mptr + 18 }};
+ uint256 internal constant NEG_S_G2_Y_1_MPTR = {{ vk_mptr + 19 }};
+ uint256 internal constant NEG_S_G2_Y_2_MPTR = {{ vk_mptr + 20 }};
+
+ uint256 internal constant CHALLENGE_MPTR = {{ challenge_mptr }};
+
+ uint256 internal constant THETA_MPTR = {{ theta_mptr }};
+ uint256 internal constant BETA_MPTR = {{ theta_mptr + 1 }};
+ uint256 internal constant GAMMA_MPTR = {{ theta_mptr + 2 }};
+ uint256 internal constant Y_MPTR = {{ theta_mptr + 3 }};
+ uint256 internal constant X_MPTR = {{ theta_mptr + 4 }};
+ {%- match scheme %}
+ {%- when Bdfg21 %}
+ uint256 internal constant ZETA_MPTR = {{ theta_mptr + 5 }};
+ uint256 internal constant NU_MPTR = {{ theta_mptr + 6 }};
+ uint256 internal constant MU_MPTR = {{ theta_mptr + 7 }};
+ {%- when Gwc19 %}
+ uint256 internal constant NU_MPTR = {{ theta_mptr + 5 }};
+ uint256 internal constant MU_MPTR = {{ theta_mptr + 6 }};
+ {%- endmatch %}
+
+ uint256 internal constant ACC_LHS_X_MPTR = {{ theta_mptr + 8 }};
+ uint256 internal constant ACC_LHS_Y_MPTR = {{ theta_mptr + 9 }};
+ uint256 internal constant ACC_RHS_X_MPTR = {{ theta_mptr + 10 }};
+ uint256 internal constant ACC_RHS_Y_MPTR = {{ theta_mptr + 11 }};
+ uint256 internal constant X_N_MPTR = {{ theta_mptr + 12 }};
+ uint256 internal constant X_N_MINUS_1_INV_MPTR = {{ theta_mptr + 13 }};
+ uint256 internal constant L_LAST_MPTR = {{ theta_mptr + 14 }};
+ uint256 internal constant L_BLIND_MPTR = {{ theta_mptr + 15 }};
+ uint256 internal constant L_0_MPTR = {{ theta_mptr + 16 }};
+ uint256 internal constant INSTANCE_EVAL_MPTR = {{ theta_mptr + 17 }};
+ uint256 internal constant QUOTIENT_EVAL_MPTR = {{ theta_mptr + 18 }};
+ uint256 internal constant QUOTIENT_X_MPTR = {{ theta_mptr + 19 }};
+ uint256 internal constant QUOTIENT_Y_MPTR = {{ theta_mptr + 20 }};
+ uint256 internal constant G1_SCALAR_MPTR = {{ theta_mptr + 21 }};
+ uint256 internal constant PAIRING_LHS_X_MPTR = {{ theta_mptr + 22 }};
+ uint256 internal constant PAIRING_LHS_Y_MPTR = {{ theta_mptr + 23 }};
+ uint256 internal constant PAIRING_RHS_X_MPTR = {{ theta_mptr + 24 }};
+ uint256 internal constant PAIRING_RHS_Y_MPTR = {{ theta_mptr + 25 }};
+
+ function verifyProof(
+ {%- match self.embedded_vk %}
+ {%- when None %}
+ address vk,
+ {%- else %}
+ {%- endmatch %}
+ bytes calldata proof,
+ uint256[] calldata instances
+ ) public returns (bool) {
+ assembly ("memory-safe") {
+ // Read EC point (x, y) at (proof_cptr, proof_cptr + 0x20),
+ // and check if the point is on affine plane,
+ // and store them in (hash_mptr, hash_mptr + 0x20).
+ // Return updated (success, proof_cptr, hash_mptr).
+ function read_ec_point(success, proof_cptr, hash_mptr, q) -> ret0, ret1, ret2 {
+ let x := calldataload(proof_cptr)
+ let y := calldataload(add(proof_cptr, 0x20))
+ ret0 := and(success, lt(x, q))
+ ret0 := and(ret0, lt(y, q))
+ ret0 := and(ret0, eq(mulmod(y, y, q), addmod(mulmod(x, mulmod(x, x, q), q), 3, q)))
+ mstore(hash_mptr, x)
+ mstore(add(hash_mptr, 0x20), y)
+ ret1 := add(proof_cptr, 0x40)
+ ret2 := add(hash_mptr, 0x40)
+ }
+
+ // Squeeze challenge by keccak256(memory[0..hash_mptr]),
+ // and store hash mod r as challenge in challenge_mptr,
+ // and push back hash in 0x00 as the first input for next squeeze.
+ // Return updated (challenge_mptr, hash_mptr).
+ function squeeze_challenge(challenge_mptr, hash_mptr, r) -> ret0, ret1 {
+ let hash := keccak256(0x00, hash_mptr)
+ mstore(challenge_mptr, mod(hash, r))
+ mstore(0x00, hash)
+ ret0 := add(challenge_mptr, 0x20)
+ ret1 := 0x20
+ }
+
+ // Squeeze challenge without absorbing new input from calldata,
+ // by putting an extra 0x01 in memory[0x20] and squeeze by keccak256(memory[0..21]),
+ // and store hash mod r as challenge in challenge_mptr,
+ // and push back hash in 0x00 as the first input for next squeeze.
+ // Return updated (challenge_mptr).
+ function squeeze_challenge_cont(challenge_mptr, r) -> ret {
+ mstore8(0x20, 0x01)
+ let hash := keccak256(0x00, 0x21)
+ mstore(challenge_mptr, mod(hash, r))
+ mstore(0x00, hash)
+ ret := add(challenge_mptr, 0x20)
+ }
+
+ // Batch invert values in memory[mptr_start..mptr_end] in place.
+ // Return updated (success).
+ function batch_invert(success, mptr_start, mptr_end, r) -> ret {
+ let gp_mptr := mptr_end
+ let gp := mload(mptr_start)
+ let mptr := add(mptr_start, 0x20)
+ for
+ {}
+ lt(mptr, sub(mptr_end, 0x20))
+ {}
+ {
+ gp := mulmod(gp, mload(mptr), r)
+ mstore(gp_mptr, gp)
+ mptr := add(mptr, 0x20)
+ gp_mptr := add(gp_mptr, 0x20)
+ }
+ gp := mulmod(gp, mload(mptr), r)
+
+ mstore(gp_mptr, 0x20)
+ mstore(add(gp_mptr, 0x20), 0x20)
+ mstore(add(gp_mptr, 0x40), 0x20)
+ mstore(add(gp_mptr, 0x60), gp)
+ mstore(add(gp_mptr, 0x80), sub(r, 2))
+ mstore(add(gp_mptr, 0xa0), r)
+ ret := and(success, staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20))
+ let all_inv := mload(gp_mptr)
+
+ let first_mptr := mptr_start
+ let second_mptr := add(first_mptr, 0x20)
+ gp_mptr := sub(gp_mptr, 0x20)
+ for
+ {}
+ lt(second_mptr, mptr)
+ {}
+ {
+ let inv := mulmod(all_inv, mload(gp_mptr), r)
+ all_inv := mulmod(all_inv, mload(mptr), r)
+ mstore(mptr, inv)
+ mptr := sub(mptr, 0x20)
+ gp_mptr := sub(gp_mptr, 0x20)
+ }
+ let inv_first := mulmod(all_inv, mload(second_mptr), r)
+ let inv_second := mulmod(all_inv, mload(first_mptr), r)
+ mstore(first_mptr, inv_first)
+ mstore(second_mptr, inv_second)
+ }
+
+ // Add (x, y) into point at (0x00, 0x20).
+ // Return updated (success).
+ function ec_add_acc(success, x, y) -> ret {
+ mstore(0x40, x)
+ mstore(0x60, y)
+ ret := and(success, staticcall(gas(), 0x06, 0x00, 0x80, 0x00, 0x40))
+ }
+
+ // Scale point at (0x00, 0x20) by scalar.
+ function ec_mul_acc(success, scalar) -> ret {
+ mstore(0x40, scalar)
+ ret := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40))
+ }
+
+ // Add (x, y) into point at (0x80, 0xa0).
+ // Return updated (success).
+ function ec_add_tmp(success, x, y) -> ret {
+ mstore(0xc0, x)
+ mstore(0xe0, y)
+ ret := and(success, staticcall(gas(), 0x06, 0x80, 0x80, 0x80, 0x40))
+ }
+
+ // Scale point at (0x80, 0xa0) by scalar.
+ // Return updated (success).
+ function ec_mul_tmp(success, scalar) -> ret {
+ mstore(0xc0, scalar)
+ ret := and(success, staticcall(gas(), 0x07, 0x80, 0x60, 0x80, 0x40))
+ }
+
+ // Perform pairing check.
+ // Return updated (success).
+ function ec_pairing(success, lhs_x, lhs_y, rhs_x, rhs_y) -> ret {
+ mstore(0x00, lhs_x)
+ mstore(0x20, lhs_y)
+ mstore(0x40, mload(G2_X_1_MPTR))
+ mstore(0x60, mload(G2_X_2_MPTR))
+ mstore(0x80, mload(G2_Y_1_MPTR))
+ mstore(0xa0, mload(G2_Y_2_MPTR))
+ mstore(0xc0, rhs_x)
+ mstore(0xe0, rhs_y)
+ mstore(0x100, mload(NEG_S_G2_X_1_MPTR))
+ mstore(0x120, mload(NEG_S_G2_X_2_MPTR))
+ mstore(0x140, mload(NEG_S_G2_Y_1_MPTR))
+ mstore(0x160, mload(NEG_S_G2_Y_2_MPTR))
+ ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20))
+ ret := and(ret, mload(0x00))
+ }
+
+ // Modulus
+ let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // BN254 base field
+ let r := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // BN254 scalar field
+
+ // Initialize success as true
+ let success := true
+
+ {
+ {%- match self.embedded_vk %}
+ {%- when Some with (embedded_vk) %}
+ // Load vk_digest and num_instances of vk into memory
+ {%- for (name, chunk) in embedded_vk.constants[..2] %}
+ mstore({{ vk_mptr + loop.index0 }}, {{ chunk|hex_padded(64) }}) // {{ name }}
+ {%- endfor %}
+ {%- when None %}
+ // Copy vk_digest and num_instances of vk into memory
+ extcodecopy(vk, VK_MPTR, 0x00, 0x40)
+ {%- endmatch %}
+
+ // Check valid length of proof
+ success := and(success, eq({{ proof_len|hex() }}, calldataload(PROOF_LEN_CPTR)))
+
+ // Check valid length of instances
+ let num_instances := mload(NUM_INSTANCES_MPTR)
+ success := and(success, eq(num_instances, calldataload(NUM_INSTANCE_CPTR)))
+
+ // Absorb vk diegst
+ mstore(0x00, mload(VK_DIGEST_MPTR))
+
+ // Read instances and witness commitments and generate challenges
+ let hash_mptr := 0x20
+ let instance_cptr := INSTANCE_CPTR
+ for
+ { let instance_cptr_end := add(instance_cptr, mul(0x20, num_instances)) }
+ lt(instance_cptr, instance_cptr_end)
+ {}
+ {
+ let instance := calldataload(instance_cptr)
+ success := and(success, lt(instance, r))
+ mstore(hash_mptr, instance)
+ instance_cptr := add(instance_cptr, 0x20)
+ hash_mptr := add(hash_mptr, 0x20)
+ }
+
+ let proof_cptr := PROOF_CPTR
+ let challenge_mptr := CHALLENGE_MPTR
+ {%- for num_advices in num_advices %}
+
+ // Phase {{ loop.index }}
+ for
+ { let proof_cptr_end := add(proof_cptr, {{ (2 * 32 * num_advices)|hex() }}) }
+ lt(proof_cptr, proof_cptr_end)
+ {}
+ {
+ success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q)
+ }
+
+ challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r)
+ {%- for _ in 0..num_challenges[loop.index0] - 1 %}
+ challenge_mptr := squeeze_challenge_cont(challenge_mptr, r)
+ {%- endfor %}
+ {%- endfor %}
+
+ // Read evaluations
+ for
+ { let proof_cptr_end := add(proof_cptr, {{ (32 * num_evals)|hex() }}) }
+ lt(proof_cptr, proof_cptr_end)
+ {}
+ {
+ let eval := calldataload(proof_cptr)
+ success := and(success, lt(eval, r))
+ mstore(hash_mptr, eval)
+ proof_cptr := add(proof_cptr, 0x20)
+ hash_mptr := add(hash_mptr, 0x20)
+ }
+
+ // Read batch opening proof and generate challenges
+ {%- match scheme %}
+ {%- when Bdfg21 %}
+ challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // zeta
+ challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) // nu
+
+ success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W
+
+ challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu
+
+ success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W'
+ {%- when Gwc19 %}
+ challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // nu
+
+ for
+ { let proof_cptr_end := add(proof_cptr, {{ (2 * 32 * num_rotations)|hex() }}) }
+ lt(proof_cptr, proof_cptr_end)
+ {}
+ {
+ success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q)
+ }
+
+ challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu
+ {%- endmatch %}
+
+ {%~ match self.embedded_vk %}
+ {%- when Some with (embedded_vk) %}
+ // Load full vk into memory
+ {%- for (name, chunk) in embedded_vk.constants %}
+ mstore({{ vk_mptr + loop.index0 }}, {{ chunk|hex_padded(64) }}) // {{ name }}
+ {%- endfor %}
+ {%- for (x, y) in embedded_vk.fixed_comms %}
+ {%- let offset = embedded_vk.constants.len() %}
+ mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x
+ mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y
+ {%- endfor %}
+ {%- for (x, y) in embedded_vk.permutation_comms %}
+ {%- let offset = embedded_vk.constants.len() + 2 * embedded_vk.fixed_comms.len() %}
+ mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x
+ mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y
+ {%- endfor %}
+ {%- when None %}
+ // Copy full vk into memory
+ extcodecopy(vk, VK_MPTR, 0x00, {{ vk_len|hex() }})
+ {%- endmatch %}
+
+ // Read accumulator from instances
+ if mload(HAS_ACCUMULATOR_MPTR) {
+ let num_limbs := mload(NUM_ACC_LIMBS_MPTR)
+ let num_limb_bits := mload(NUM_ACC_LIMB_BITS_MPTR)
+
+ let cptr := add(INSTANCE_CPTR, mul(mload(ACC_OFFSET_MPTR), 0x20))
+ let lhs_y_off := mul(num_limbs, 0x20)
+ let rhs_x_off := mul(lhs_y_off, 2)
+ let rhs_y_off := mul(lhs_y_off, 3)
+ let lhs_x := calldataload(cptr)
+ let lhs_y := calldataload(add(cptr, lhs_y_off))
+ let rhs_x := calldataload(add(cptr, rhs_x_off))
+ let rhs_y := calldataload(add(cptr, rhs_y_off))
+ for
+ {
+ let cptr_end := add(cptr, mul(0x20, num_limbs))
+ let shift := num_limb_bits
+ }
+ lt(cptr, cptr_end)
+ {}
+ {
+ cptr := add(cptr, 0x20)
+ lhs_x := add(lhs_x, shl(shift, calldataload(cptr)))
+ lhs_y := add(lhs_y, shl(shift, calldataload(add(cptr, lhs_y_off))))
+ rhs_x := add(rhs_x, shl(shift, calldataload(add(cptr, rhs_x_off))))
+ rhs_y := add(rhs_y, shl(shift, calldataload(add(cptr, rhs_y_off))))
+ shift := add(shift, num_limb_bits)
+ }
+
+ success := and(success, and(lt(lhs_x, q), lt(lhs_y, q)))
+ success := and(success, eq(mulmod(lhs_y, lhs_y, q), addmod(mulmod(lhs_x, mulmod(lhs_x, lhs_x, q), q), 3, q)))
+ success := and(success, and(lt(rhs_x, q), lt(rhs_y, q)))
+ success := and(success, eq(mulmod(rhs_y, rhs_y, q), addmod(mulmod(rhs_x, mulmod(rhs_x, rhs_x, q), q), 3, q)))
+
+ mstore(ACC_LHS_X_MPTR, lhs_x)
+ mstore(ACC_LHS_Y_MPTR, lhs_y)
+ mstore(ACC_RHS_X_MPTR, rhs_x)
+ mstore(ACC_RHS_Y_MPTR, rhs_y)
+ }
+
+ pop(q)
+ }
+
+ // Return 0 early if anything from calldata is invalid
+ if iszero(success) {
+ mstore(0x00, 0)
+ return(0x00, 0x20)
+ }
+
+ // Compute lagrange evaluations and instance evaluation
+ {
+ let k := mload(K_MPTR)
+ let x := mload(X_MPTR)
+ let x_n := x
+ for
+ { let idx := 0 }
+ lt(idx, k)
+ { idx := add(idx, 1) }
+ {
+ x_n := mulmod(x_n, x_n, r)
+ }
+
+ let omega := mload(OMEGA_MPTR)
+
+ let mptr := X_N_MPTR
+ let mptr_end := add(mptr, mul(0x20, add(mload(NUM_INSTANCES_MPTR), {{ num_neg_lagranges }})))
+ if iszero(mload(NUM_INSTANCES_MPTR)) {
+ mptr_end := add(mptr_end, 0x20)
+ }
+ for
+ { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) }
+ lt(mptr, mptr_end)
+ { mptr := add(mptr, 0x20) }
+ {
+ mstore(mptr, addmod(x, sub(r, pow_of_omega), r))
+ pow_of_omega := mulmod(pow_of_omega, omega, r)
+ }
+ let x_n_minus_1 := addmod(x_n, sub(r, 1), r)
+ mstore(mptr_end, x_n_minus_1)
+ success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), r)
+
+ mptr := X_N_MPTR
+ let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r)
+ for
+ { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) }
+ lt(mptr, mptr_end)
+ { mptr := add(mptr, 0x20) }
+ {
+ mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r))
+ pow_of_omega := mulmod(pow_of_omega, omega, r)
+ }
+
+ let l_blind := mload(add(X_N_MPTR, 0x20))
+ let l_i_cptr := add(X_N_MPTR, 0x40)
+ for
+ { let l_i_cptr_end := add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }}) }
+ lt(l_i_cptr, l_i_cptr_end)
+ { l_i_cptr := add(l_i_cptr, 0x20) }
+ {
+ l_blind := addmod(l_blind, mload(l_i_cptr), r)
+ }
+
+ let instance_eval := 0
+ for
+ {
+ let instance_cptr := INSTANCE_CPTR
+ let instance_cptr_end := add(instance_cptr, mul(0x20, mload(NUM_INSTANCES_MPTR)))
+ }
+ lt(instance_cptr, instance_cptr_end)
+ {
+ instance_cptr := add(instance_cptr, 0x20)
+ l_i_cptr := add(l_i_cptr, 0x20)
+ }
+ {
+ instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r)
+ }
+
+ let x_n_minus_1_inv := mload(mptr_end)
+ let l_last := mload(X_N_MPTR)
+ let l_0 := mload(add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }}))
+
+ mstore(X_N_MPTR, x_n)
+ mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv)
+ mstore(L_LAST_MPTR, l_last)
+ mstore(L_BLIND_MPTR, l_blind)
+ mstore(L_0_MPTR, l_0)
+ mstore(INSTANCE_EVAL_MPTR, instance_eval)
+ }
+
+ // Compute quotient evavluation
+ {
+ let quotient_eval_numer
+ let delta := 4131629893567559867359510883348571134090853742863529169391034518566172092834
+ let y := mload(Y_MPTR)
+
+ {%- for code_block in quotient_eval_numer_computations %}
+ {
+ {%- for line in code_block %}
+ {{ line }}
+ {%- endfor %}
+ }
+ {%- endfor %}
+
+ pop(y)
+ pop(delta)
+
+ let quotient_eval := mulmod(quotient_eval_numer, mload(X_N_MINUS_1_INV_MPTR), r)
+ mstore(QUOTIENT_EVAL_MPTR, quotient_eval)
+ }
+
+ // Compute quotient commitment
+ {
+ mstore(0x00, calldataload(LAST_QUOTIENT_X_CPTR))
+ mstore(0x20, calldataload(add(LAST_QUOTIENT_X_CPTR, 0x20)))
+ let x_n := mload(X_N_MPTR)
+ for
+ {
+ let cptr := sub(LAST_QUOTIENT_X_CPTR, 0x40)
+ let cptr_end := sub(FIRST_QUOTIENT_X_CPTR, 0x40)
+ }
+ lt(cptr_end, cptr)
+ {}
+ {
+ success := ec_mul_acc(success, x_n)
+ success := ec_add_acc(success, calldataload(cptr), calldataload(add(cptr, 0x20)))
+ cptr := sub(cptr, 0x40)
+ }
+ mstore(QUOTIENT_X_MPTR, mload(0x00))
+ mstore(QUOTIENT_Y_MPTR, mload(0x20))
+ }
+
+ // Compute pairing lhs and rhs
+ {
+ {%- for code_block in pcs_computations %}
+ {
+ {%- for line in code_block %}
+ {{ line }}
+ {%- endfor %}
+ }
+ {%- endfor %}
+ }
+
+ // Random linear combine with accumulator
+ if mload(HAS_ACCUMULATOR_MPTR) {
+ mstore(0x00, mload(ACC_LHS_X_MPTR))
+ mstore(0x20, mload(ACC_LHS_Y_MPTR))
+ mstore(0x40, mload(ACC_RHS_X_MPTR))
+ mstore(0x60, mload(ACC_RHS_Y_MPTR))
+ mstore(0x80, mload(PAIRING_LHS_X_MPTR))
+ mstore(0xa0, mload(PAIRING_LHS_Y_MPTR))
+ mstore(0xc0, mload(PAIRING_RHS_X_MPTR))
+ mstore(0xe0, mload(PAIRING_RHS_Y_MPTR))
+ let challenge := mod(keccak256(0x00, 0x100), r)
+
+ // [pairing_lhs] += challenge * [acc_lhs]
+ success := ec_mul_acc(success, challenge)
+ success := ec_add_acc(success, mload(PAIRING_LHS_X_MPTR), mload(PAIRING_LHS_Y_MPTR))
+ mstore(PAIRING_LHS_X_MPTR, mload(0x00))
+ mstore(PAIRING_LHS_Y_MPTR, mload(0x20))
+
+ // [pairing_rhs] += challenge * [acc_rhs]
+ mstore(0x00, mload(ACC_RHS_X_MPTR))
+ mstore(0x20, mload(ACC_RHS_Y_MPTR))
+ success := ec_mul_acc(success, challenge)
+ success := ec_add_acc(success, mload(PAIRING_RHS_X_MPTR), mload(PAIRING_RHS_Y_MPTR))
+ mstore(PAIRING_RHS_X_MPTR, mload(0x00))
+ mstore(PAIRING_RHS_Y_MPTR, mload(0x20))
+ }
+
+ // Perform pairing
+ success := ec_pairing(
+ success,
+ mload(PAIRING_LHS_X_MPTR),
+ mload(PAIRING_LHS_Y_MPTR),
+ mload(PAIRING_RHS_X_MPTR),
+ mload(PAIRING_RHS_Y_MPTR)
+ )
+
+ // Return 0 if anything fails
+ if iszero(success) {
+ mstore(0x00, 0)
+ return(0x00, 0x20)
+ }
+
+ // Return 1 as result if everything succeeds
+ mstore(0x00, 1)
+ return(0x00, 0x20)
+ }
+ }
+}
diff --git a/crates/halo2-verifier/templates/Halo2VerifyingKey.sol b/crates/halo2-verifier/templates/Halo2VerifyingKey.sol
new file mode 100644
index 00000000..6469916d
--- /dev/null
+++ b/crates/halo2-verifier/templates/Halo2VerifyingKey.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity 0.8.26;
+
+contract Halo2VerifyingKey {
+ constructor() {
+ assembly {
+ {%- for (name, chunk) in constants %}
+ mstore({{ (32 * loop.index0)|hex_padded(4) }}, {{ chunk|hex_padded(64) }}) // {{ name }}
+ {%- endfor %}
+ {%- for (x, y) in fixed_comms %}
+ {%- let offset = constants.len() %}
+ mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x
+ mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y
+ {%- endfor %}
+ {%- for (x, y) in permutation_comms %}
+ {%- let offset = constants.len() + 2 * fixed_comms.len() %}
+ mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x
+ mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y
+ {%- endfor %}
+
+ return(0, {{ (32 * (constants.len() + 2 * fixed_comms.len() + 2 * permutation_comms.len()))|hex() }})
+ }
+ }
+}
diff --git a/crates/integration-tests/Cargo.toml b/crates/integration-tests/Cargo.toml
new file mode 100644
index 00000000..166ddf36
--- /dev/null
+++ b/crates/integration-tests/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "integration-tests"
+version = "0.1.0"
+edition.workspace = true
+authors.workspace = true
+homepage.workspace = true
+license.workspace = true
+categories.workspace = true
+repository.workspace = true
+
+[dependencies]
+alloy-contract = { workspace = true }
+alloy-primitives = { workspace = true }
+alloy-sol-types = { workspace = true, features = ["json"] }
+evm-utils = { workspace = true }
+halo2_proofs = { workspace = true }
+halo2_solidity_verifier = { workspace = true }
+hex = { workspace = true }
+rand = { workspace = true, features = ["small_rng"] }
+rstest = { workspace = true }
+serde = { workspace = true }
+serde_json = { workspace = true }
+shielder-circuits = { workspace = true }
+shielder-rust-sdk = { workspace = true, features = ["account", "contract", "conversion", "parameter_generation", "powers_of_tau", "permit2"] }
diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs
new file mode 100644
index 00000000..5096d00a
--- /dev/null
+++ b/crates/integration-tests/src/lib.rs
@@ -0,0 +1,32 @@
+#![cfg(test)]
+#![feature(assert_matches)]
+
+use std::{fs::File, io::Read};
+
+use alloy_primitives::Address;
+use evm_utils::{compilation::source_to_bytecode, EvmRunner};
+
+mod permit2;
+mod poseidon2;
+mod proving_utils;
+mod shielder;
+mod token;
+mod verifier;
+
+const CONTRACTS_DIR: &str = "../../contracts";
+
+fn read_contract(contract_name: &str) -> String {
+ let mut contents = String::new();
+ let mut file = File::open(format!("{CONTRACTS_DIR}/{contract_name}"))
+ .expect("Cannot open contract source file");
+ file.read_to_string(&mut contents)
+ .expect("Cannot read contract source file");
+ contents
+}
+
+fn deploy_contract(contract_filename: &str, contract_name: &str, evm: &mut EvmRunner) -> Address {
+ let solidity_code = read_contract(contract_filename);
+ let compiled_bytecode = source_to_bytecode(solidity_code, contract_name, true);
+ evm.create(compiled_bytecode, None)
+ .unwrap_or_else(|_| panic!("Failed to deploy {contract_name} contract"))
+}
diff --git a/crates/integration-tests/src/permit2.rs b/crates/integration-tests/src/permit2.rs
new file mode 100644
index 00000000..3eedb04e
--- /dev/null
+++ b/crates/integration-tests/src/permit2.rs
@@ -0,0 +1,26 @@
+use alloy_sol_types::{sol, SolCall};
+use shielder_rust_sdk::permit2::{get_eip712_hash, sign_message, PermitTransferFrom};
+
+// @dev compile the SC suite with forge and:
+// cat artifacts/Permit2.sol/Permit2.json | jq .bytecode.object
+pub const PERMIT2_BYTECODE: &str = "60c0346100bb574660a052602081017f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408301524660608301523060808301526080825260a082019180831060018060401b038411176100a55782604052519020608052611b5990816100c18239608051816114c4015260a0518161149e0152f35b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db14610e9f578063137c29fe14610d1c5780632a2d80d114610abd5780632b67b5701461094757806330f28b7a146108845780633644e5151461086157806336c78516146108175780633ff9dcb1146107b55780634fe02b441461077657806365d9723c1461066657806387517c4514610584578063927da105146104f8578063cc53287f14610417578063edd9444b146102eb5763fe8ec1a7146100c657600080fd5b346102e75760c03660031901126102e7576001600160401b0383358181116102e3576100f59036908601611185565b6024358281116102df5761010c9036908701611155565b610114611069565b916084358581116102db5761012c9036908a016110fe565b98909560a4359081116102d757610145913691016110fe565b96909581519061015482610fcb565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301526a0d88191958591b1a5b994b60aa1b608083015282519a8b91816101f16020850180966117e7565b918237018a8152039961020c601f199b8c8101835282611001565b5190209085515161021c81611763565b908a5b8181106102aa5750506102a7999a61029e918351610251816102456020820180956117ba565b03848101835282611001565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611001565b5190209361161a565b80f35b806102c26102bc6102d2938c5161127e565b51611899565b6102cc828661127e565b52611795565b61021f565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346102e75760803660031901126102e7576001600160401b039080358281116102e35761031d9036908301611185565b6024358381116102df576103349036908401611155565b93909261033f611069565b9160643590811161041357610356913691016110fe565b9490938351519761036689611763565b98885b8181106103f15750506102a7979881516103998161038b6020820180956117ba565b03601f198101835282611001565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a0815261029e81610fe6565b808b6102cc826104086102bc61040e968d5161127e565b9261127e565b610369565b8680fd5b5082346104f457602090816003193601126102e3578035906001600160401b0382116102df5761044991369101611155565b929091845b848110610459578580f35b8061046f61046a600193888861136c565b61137c565b6104848461047e848a8a61136c565b0161137c565b33895283855285892091848060a01b0380911692838b528652868a20911690818a5285528589206bffffffffffffffffffffffff60a01b81541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a20161044e565b8280fd5b50346102e75760603660031901126102e7576105808161051661103d565b9361051f611053565b610527611069565b6001600160a01b03968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346102e75760803660031901126102e75761059e61103d565b906105a7611053565b916105b0611069565b906064359265ffffffffffff93848116908181036102db577fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b9333895260016020528389209660018060a01b0380921697888b5260205281858b20991698898b52602052848a2092841560001461065e57504216905b82546001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795169485179055815193845260208401523392a480f35b905090610626565b5082346104f45760603660031901126104f45761068161103d565b9061068a611053565b9265ffffffffffff60443581811693908481036102db57338852602091600183528489209660018060a01b0380911697888b528452858a20981697888a5283528489205460d01c93848711156107675761ffff90858403161161075957503380895260018352848920878a528352848920888a52835284892080546001600160d01b031660d09390931b6001600160d01b03191692909217909155835194855290840191909152917f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f39190a480f35b8451631269ad1360e11b8152fd5b508451633ab3447f60e11b8152fd5b50346102e757806003193601126102e75760209181906001600160a01b0361079c61103d565b1681528084528181206024358252845220549051908152f35b5082346104f457816003193601126104f4577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b823461085e57608036600319011261085e5761083161103d565b610839611053565b610841611069565b606435916001600160a01b03831683036102df576102a7936112a8565b80fd5b50346102e757816003193601126102e75760209061087d61149b565b9051908152f35b508290346104f4576101003660031901126104f4576108a236611093565b90806083193601126102e3576108b6611022565b9160e4356001600160401b038111610943576102a7946108d8913691016110fe565b9390926108e58351611899565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a0815261093a81610fe6565b51902091611587565b8580fd5b5091346102e7576101003660031901126102e75761096361103d565b366023190160c081126102e357608085519161097e83610fb0565b126102e35784519061098f82610f7f565b6001600160a01b03916024358381168103610413578152604435838116810361041357602082015265ffffffffffff60643581811681036102db57888301526084359081168103610413576060820152815260a435938285168503610943576020820194855260c4359087830182815260e4356001600160401b0381116102d757610a1d90369084016110fe565b929093804211610aa7575050918591610a976102a7999a610a9d95610a428851611812565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610a8f81610fcb565b519020611556565b916118fe565b5192511691611390565b8a5163cd21db4f60e01b81529182015260249150fd5b5091346102e75760606003199381853601126102e357610adb61103d565b926024908135926001600160401b03978885116102db57859085360301126104135780519785890189811082821117610d0a578252848301358181116102d757850190366023830112156102d7578382013591610b378361112b565b90610b4485519283611001565b838252602093878584019160071b83010191368311610d06578801905b828210610ca9575050508a526044610b7a86880161107f565b96838c01978852013594838b0191868352604435908111610ca557610ba290369087016110fe565b959096804211610c93575050508998995151610bbd81611763565b908b5b818110610c7057505092889492610a9792610c3d97958351610be98161038b86820180956117ba565b5190209060018060a01b039a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610a8f81610fcb565b51169082515192845b848110610c51578580f35b80610c6a8585610c64600195875161127e565b51611390565b01610c46565b806102c2610c858e9f9e93610c8b945161127e565b51611812565b9b9a9b610bc0565b855163cd21db4f60e01b815291820152fd5b8a80fd5b608082360312610d0657856080918851610cc281610f7f565b610ccb8561107f565b8152610cd883860161107f565b83820152610ce78a8601611142565b8a8201528d610cf7818701611142565b90820152815201910190610b61565b8c80fd5b634e487b7160e01b8952604184528489fd5b5082346104f4576101403660031901126104f457610d3936611093565b91806083193601126102e357610d4d611022565b6001600160401b0393906101043585811161041357610d6f90369086016110fe565b9093610124359687116102db57610d8f61093a966102a7983691016110fe565b969095825190610d9e82610fcb565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c6060830152631a5b994b60e21b6080830152835194859181610e346020850180966117e7565b918237018b81520393610e4f601f1995868101835282611001565b51902092610e5d8651611899565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e08101610292565b5082346104f4576020806003193601126102e35781356001600160401b03928382116109435736602383011215610943578101359283116102df576024906007368386831b8401011161041357865b858110610ef9578780f35b80821b830190608060231983360301126102d757610f79888760019460608351610f2281610f7f565b610f5e6084610f328d860161107f565b94858452610f426044820161107f565b8097850152610f536064820161107f565b80988501520161107f565b9182910152868060a01b0380808093169516931691166112a8565b01610eee565b608081019081106001600160401b03821117610f9a57604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b03821117610f9a57604052565b60a081019081106001600160401b03821117610f9a57604052565b60c081019081106001600160401b03821117610f9a57604052565b90601f801991011681019081106001600160401b03821117610f9a57604052565b60c435906001600160a01b038216820361103857565b600080fd5b600435906001600160a01b038216820361103857565b602435906001600160a01b038216820361103857565b604435906001600160a01b038216820361103857565b35906001600160a01b038216820361103857565b6003190190608082126110385760408051906110ae82610fb0565b808294126110385780518181018181106001600160401b03821117610f9a5782526004356001600160a01b0381168103611038578152602435602082015282526044356020830152606435910152565b9181601f84011215611038578235916001600160401b038311611038576020838186019501011161103857565b6001600160401b038111610f9a5760051b60200190565b359065ffffffffffff8216820361103857565b9181601f84011215611038578235916001600160401b038311611038576020808501948460061b01011161103857565b9190916060818403126110385760408051916111a083610fb0565b829481356001600160401b039081811161103857830182601f820112156110385780356111cc8161112b565b926111d987519485611001565b818452602094858086019360061b85010193818511611038579086899897969594939201925b84841061121c575050505050855280820135908501520135910152565b909192939495969784830312611038578851908982019082821085831117611269578a928992845261124d8761107f565b81528287013583820152815201930191908897969594936111ff565b60246000634e487b7160e01b81526041600452fd5b80518210156112925760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b92919260018060a01b03604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c1680421161135457508287169683880361130b575b505061130995501692611ad0565b565b87848416116000146113305760405163f96fb07160e01b815260048101899052602490fd5b8383611309990316906bffffffffffffffffffffffff60a01b1617905538806112fb565b60249060405190636c0d979760e11b82526004820152fd5b91908110156112925760061b0190565b356001600160a01b03811681036110385790565b9065ffffffffffff908160608401511660018060a01b03908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c0361148a57918561147e94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec989796945087156000146114835742165b6001850160d01b6001600160d01b03191660a09190911b65ffffffffffff60a01b1617179055516001600160a01b03909316835265ffffffffffff938416602084015290921660408201529081906060820190565b0390a4565b5086611429565b8351633ab3447f60e11b8152600490fd5b467f0000000000000000000000000000000000000000000000000000000000000000036114e6577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408201524660608201523060808201526080815261155081610fcb565b51902090565b61155e61149b565b9060405190602082019261190160f01b8452602283015260428201526042815261155081610f7f565b9192909360a43593604084015180421161160257506020845101518086116115ea5750918591610a976115c7946115c2602088015186611715565b611556565b51516001600160a01b039081169260843591821682036110385761130993611ad0565b60249060405190633728b83d60e01b82526004820152fd5b6024906040519063cd21db4f60e01b82526004820152fd5b9590939580515195604092838301518042116116fe57508488036116ea57611651918691610a9760209b6115c28d88015186611715565b60005b868110611665575050505050505050565b61167081835161127e565b518861167d83878a61136c565b013590898101518083116116d35750918188888860019685966116a7575b50505050505001611654565b6116c8956116c29261046a928a8060a01b039051169561136c565b91611ad0565b80388888888361169b565b602490865190633728b83d60e01b82526004820152fd5b83516001621398b960e31b03198152600490fd5b60249085519063cd21db4f60e01b82526004820152fd5b90600160ff82161b9160018060a01b0316600052600060205260406000209060081c600052602052604060002081815418809155161561175157565b604051633ab3447f60e11b8152600490fd5b9061176d8261112b565b61177a6040519182611001565b828152809261178b601f199161112b565b0190602036910137565b60001981146117a45760010190565b634e487b7160e01b600052601160045260246000fd5b805160208092019160005b8281106117d3575050505090565b8351855293810193928101926001016117c5565b9081519160005b8381106117ff575050016000815290565b80602080928401015181850152016117ee565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835260018060a01b038082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c081018181106001600160401b03821117610f9a5760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845260018060a01b038151166040840152015160608201526060815261155081610f7f565b9190826040910312611038576020823592013590565b6000843b6119f75750604182036119a75761191b828201826118e8565b939092604010156112925760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa1561199b576000516001600160a01b0390811691821561198957160361197757565b604051632057875960e21b8152600490fd5b604051638baa579f60e01b8152600490fd5b6040513d6000823e3d90fd5b604082036119e5576119bb918101906118e8565b6001600160ff1b0381169260ff91821c601b019182116117a45760209360009360ff608094611939565b604051634be6321b60e01b8152600490fd5b918093946020926064604051809781958294630b135d3f60e11b9b8c8552600485015260406024850152816044850152848401378181018301889052601f01601f191681010301916001600160a01b03165afa918215611ac3578192611a7d575b50506001600160e01b03191603611a6b57565b604051632c19a72f60e21b8152600490fd5b9091506020813d8211611abb575b81611a9860209383611001565b810103126102e75751906001600160e01b03198216820361085e57503880611a58565b3d9150611a8b565b50604051903d90823e3d90fd5b9060006064926020958295604051946323b872dd60e01b86526004860152602485015260448401525af13d15601f3d1160016000511416171615611b1057565b60405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606490fdfea164736f6c6343000811000a";
+
+sol! {
+ function DOMAIN_SEPARATOR() public view override returns (bytes32);
+}
+
+pub fn domain_separator_calldata() -> Vec {
+ DOMAIN_SEPARATORCall {}.abi_encode()
+}
+
+pub fn sign_permit(
+ permit: &PermitTransferFrom,
+ eip712_domain_separator: &[u8; 32],
+ private_key: &[u8; 32],
+) -> Vec {
+ let message = get_eip712_hash(permit, eip712_domain_separator);
+
+ let (r, s, v) = sign_message(&message, private_key);
+
+ [r.to_vec(), s.to_vec(), vec![v]].concat()
+}
diff --git a/crates/integration-tests/src/poseidon2.rs b/crates/integration-tests/src/poseidon2.rs
new file mode 100644
index 00000000..796d8ca5
--- /dev/null
+++ b/crates/integration-tests/src/poseidon2.rs
@@ -0,0 +1,43 @@
+use alloy_primitives::U256;
+use alloy_sol_types::{sol, SolCall, SolValue};
+use evm_utils::{EvmRunner, SuccessResult};
+use halo2_proofs::halo2curves::bn256::Fr;
+use shielder_circuits::utils::hash;
+use shielder_rust_sdk::conversion::field_to_u256;
+
+use crate::deploy_contract;
+
+const POSEIDON2_CONTRACT_NAME: &str = "Poseidon2T8Assembly";
+const POSEIDON2_FILE_NAME: &str = "Poseidon2T8Assembly.sol";
+
+sol! {
+ function hash(uint[7] memory) public pure returns (uint);
+}
+
+fn encode_calldata(values: &[Fr; 7]) -> Vec {
+ let values = values
+ .iter()
+ .map(field_to_u256::)
+ .collect::>();
+ let values = values.try_into().unwrap();
+ hashCall { _0: values }.abi_encode()
+}
+
+#[test]
+fn verify_off_chain_and_on_chain_poseidon_preimage() {
+ let preimage = [1, 2, 3, 4, 5, 6, 7].map(Fr::from);
+
+ let mut evm = EvmRunner::aleph_evm();
+ let poseidon2_address = deploy_contract(POSEIDON2_FILE_NAME, POSEIDON2_CONTRACT_NAME, &mut evm);
+
+ let calldata = encode_calldata(&preimage);
+ let response = match evm.call(poseidon2_address, calldata, None, None) {
+ Ok(SuccessResult { output, .. }) => output,
+ Err(why) => panic!("Failed to call Poseidon2 contract: {why}"),
+ };
+
+ let image_on_chain = ::abi_decode(&response, true).unwrap();
+ let image_off_chain = hash(&preimage);
+
+ assert_eq!(image_on_chain, field_to_u256(image_off_chain));
+}
diff --git a/crates/integration-tests/src/proving_utils.rs b/crates/integration-tests/src/proving_utils.rs
new file mode 100644
index 00000000..d5278631
--- /dev/null
+++ b/crates/integration-tests/src/proving_utils.rs
@@ -0,0 +1,77 @@
+use halo2_proofs::plonk::Circuit;
+use rand::{RngCore, SeedableRng};
+use rstest::fixture;
+use shielder_circuits::{
+ circuits::{Params, ProvingKey, VerifyingKey},
+ consts::RANGE_PROOF_CHUNK_SIZE,
+ deposit::DepositCircuit,
+ generate_keys_with_min_k, generate_proof,
+ new_account::NewAccountCircuit,
+ verify,
+ withdraw::WithdrawCircuit,
+ ProverKnowledge, F, MAX_K,
+};
+use shielder_rust_sdk::{
+ parameter_generation,
+ powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format},
+};
+
+/// Given circuit type `C`, construct a correct relation instance and generate a proof, accompanied
+/// by the corresponding public input.
+pub fn prepare_proof>() -> (Vec, Vec) {
+ let (params, pk, vk, mut rng) = setup::();
+
+ let prover_knowledge = PK::random_correct_example(&mut rng);
+ let circuit = prover_knowledge.create_circuit();
+ let pub_input = prover_knowledge.serialize_public_input();
+
+ let proof = generate_proof(¶ms, &pk, circuit, &pub_input, &mut rng);
+
+ // Canary check - should be already covered in other tests.
+ verify(¶ms, &vk, &proof, &pub_input).expect("Verification failed");
+
+ (proof, pub_input)
+}
+
+/// Given circuit type `C`, generate params and a proving key.
+pub fn prepare_proving_keys + Default>() -> (Params, ProvingKey) {
+ let (params, pk, _, _) = setup::();
+ (params, pk)
+}
+
+fn setup + Default>() -> (Params, ProvingKey, VerifyingKey, impl SeedableRng + RngCore)
+{
+ let full_params = read_setup_parameters(
+ get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau),
+ Format::PerpetualPowersOfTau,
+ )
+ .expect("failed to read parameters from the ptau file");
+
+ let (params, _, pk, vk) =
+ generate_keys_with_min_k::(full_params).expect("Key generation failed");
+
+ (params, pk, vk, parameter_generation::rng())
+}
+
+pub type ProvingParams = (Params, ProvingKey);
+
+#[fixture]
+#[once]
+pub fn new_account_native_proving_params() -> ProvingParams {
+ println!("Preparing NewAccountNative proving keys");
+ prepare_proving_keys::>()
+}
+
+#[fixture]
+#[once]
+pub fn deposit_native_proving_params() -> ProvingParams {
+ println!("Preparing DepositNative proving keys");
+ prepare_proving_keys::>()
+}
+
+#[fixture]
+#[once]
+pub fn withdraw_native_proving_params() -> ProvingParams {
+ println!("Preparing WithdrawNative proving keys");
+ prepare_proving_keys::>()
+}
diff --git a/crates/integration-tests/src/shielder/address_conversion.rs b/crates/integration-tests/src/shielder/address_conversion.rs
new file mode 100644
index 00000000..78094345
--- /dev/null
+++ b/crates/integration-tests/src/shielder/address_conversion.rs
@@ -0,0 +1,32 @@
+use alloy_primitives::{address, U256};
+use alloy_sol_types::{sol, SolCall, SolValue};
+use halo2_proofs::halo2curves::bn256::Fr;
+use rstest::rstest;
+use shielder_rust_sdk::conversion::{address_to_field, field_to_u256};
+
+use crate::shielder::deploy::{deployment, Deployment};
+
+sol! {
+ function addressToUInt256(address addr) public pure returns (uint256);
+}
+
+#[rstest]
+fn verify_off_chain_and_on_chain_address_to_u256_conversion(mut deployment: Deployment) {
+ let some_address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
+
+ let on_chain_result = deployment
+ .evm
+ .call(
+ deployment.contract_suite.shielder,
+ addressToUInt256Call { addr: some_address }.abi_encode(),
+ None,
+ None,
+ )
+ .expect("Failed to convert address to field on-chain");
+ let on_chain = ::abi_decode(&on_chain_result.output, true)
+ .expect("Failed to decode on-chain result");
+
+ let off_chain = field_to_u256(address_to_field::(some_address));
+
+ assert_eq!(on_chain, off_chain);
+}
diff --git a/crates/integration-tests/src/shielder/calls/deposit_native.rs b/crates/integration-tests/src/shielder/calls/deposit_native.rs
new file mode 100644
index 00000000..53cb61bd
--- /dev/null
+++ b/crates/integration-tests/src/shielder/calls/deposit_native.rs
@@ -0,0 +1,268 @@
+use std::assert_matches::assert_matches;
+
+use alloy_primitives::{Bytes, TxHash, U256};
+use rstest::rstest;
+use shielder_rust_sdk::{
+ account::{
+ call_data::{DepositCallType, MerkleProof},
+ ShielderAccount,
+ },
+ contract::ShielderContract::{
+ depositNativeCall, DepositNative, ShielderContractErrors, ShielderContractEvents,
+ },
+};
+
+use crate::shielder::{
+ actor_balance_decreased_by,
+ calls::new_account_native,
+ deploy::{deployment, Deployment},
+ invoke_shielder_call,
+ limits::{get_deposit_limit, set_deposit_limit},
+ merkle::get_merkle_args,
+ CallResult,
+};
+
+pub fn prepare_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ amount: U256,
+) -> (depositNativeCall, U256) {
+ let note_index = shielder_account
+ .current_leaf_index()
+ .expect("No leaf index");
+
+ let (params, pk) = deployment.deposit_native_proving_params.clone();
+ let (merkle_root, merkle_path) = get_merkle_args(
+ deployment.contract_suite.shielder,
+ note_index,
+ &mut deployment.evm,
+ );
+ let calldata = shielder_account.prepare_call::(
+ ¶ms,
+ &pk,
+ U256::from(amount),
+ &MerkleProof {
+ root: merkle_root,
+ path: merkle_path,
+ },
+ );
+ (calldata, note_index)
+}
+
+pub fn invoke_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ amount: U256,
+ calldata: &depositNativeCall,
+) -> CallResult {
+ let call_result = invoke_shielder_call(deployment, calldata, Some(amount));
+
+ match call_result {
+ Ok(event) => {
+ shielder_account.register_action((TxHash::default(), event.clone()));
+ Ok(event)
+ }
+ Err(_) => call_result,
+ }
+}
+
+#[rstest]
+fn succeeds(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10))
+ .unwrap();
+
+ let amount = U256::from(5);
+ let (calldata, note_index) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_eq!(
+ result,
+ Ok(ShielderContractEvents::DepositNative(DepositNative {
+ idHiding: calldata.idHiding,
+ amount: U256::from(amount),
+ newNote: calldata.newNote,
+ newNoteIndex: note_index.saturating_add(U256::from(1)),
+ }))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(15)));
+ assert_eq!(shielder_account.shielded_amount, U256::from(15))
+}
+
+#[rstest]
+fn can_consume_entire_contract_balance_limit(mut deployment: Deployment) {
+ let mut shielder_account = new_account_native::create_account_and_call(
+ &mut deployment,
+ U256::from(1),
+ U256::from((1u128 << 112) - 2),
+ )
+ .unwrap();
+
+ let amount = U256::from(1);
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert!(result.is_ok());
+ assert!(actor_balance_decreased_by(
+ &deployment,
+ U256::from((1u128 << 112) - 1)
+ ))
+}
+
+#[rstest]
+fn fails_if_contract_balance_limit_reached(mut deployment: Deployment) {
+ let mut shielder_account = new_account_native::create_account_and_call(
+ &mut deployment,
+ U256::from(1),
+ U256::from((1u128 << 112) - 1),
+ )
+ .unwrap();
+
+ let amount = U256::from(1);
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::ContractBalanceLimitReached(_))
+ );
+ assert!(actor_balance_decreased_by(
+ &deployment,
+ U256::from((1u128 << 112) - 1)
+ ))
+}
+
+#[rstest]
+fn correctly_handles_max_u256_value(mut deployment: Deployment) {
+ let initial_amount = U256::from(10);
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount)
+ .unwrap();
+
+ let amount = U256::MAX - initial_amount;
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::ContractBalanceLimitReached(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(10)))
+}
+
+#[rstest]
+fn cannot_use_same_note_twice(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10))
+ .unwrap();
+
+ let amount = U256::from(5);
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result_1 = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+ assert!(result_1.is_ok());
+
+ let result_2 = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result_2,
+ Err(ShielderContractErrors::DuplicatedNullifier(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(15)))
+}
+
+#[rstest]
+fn fails_if_merkle_root_does_not_exist(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+
+ let calldata = depositNativeCall {
+ idHiding: U256::ZERO,
+ oldNullifierHash: U256::ZERO,
+ newNote: U256::ZERO,
+ merkleRoot: U256::ZERO,
+ proof: Bytes::from(vec![]),
+ };
+ let result = invoke_call(
+ &mut deployment,
+ &mut shielder_account,
+ U256::from(10),
+ &calldata,
+ );
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::MerkleRootDoesNotExist(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::ZERO))
+}
+
+#[rstest]
+fn fails_if_proof_incorrect(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10))
+ .unwrap();
+
+ let amount = U256::from(5);
+ let (mut calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ calldata.proof = Bytes::from(vec![]);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::DepositVerificationFailed(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(10)))
+}
+
+#[rstest]
+fn rejects_value_zero(mut deployment: Deployment) {
+ let initial_amount = U256::from(10);
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount)
+ .unwrap();
+
+ let amount = U256::ZERO;
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::ZeroAmount(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(10)))
+}
+
+#[rstest]
+fn fails_if_over_deposit_limit(mut deployment: Deployment) {
+ let initial_amount = U256::from(101);
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount)
+ .unwrap();
+
+ let amount = U256::from(1);
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert!(result.is_ok());
+
+ let old_limit = get_deposit_limit(&mut deployment);
+
+ assert_eq!(old_limit, U256::MAX);
+
+ let new_limit = U256::from(100);
+ set_deposit_limit(&mut deployment, new_limit);
+
+ let returned_new_limit = get_deposit_limit(&mut deployment);
+
+ assert_eq!(returned_new_limit, U256::from(100));
+
+ let initial_amount = U256::from(10);
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(2), initial_amount)
+ .unwrap();
+
+ let amount = U256::from(101);
+ let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount);
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::AmountOverDepositLimit(_))
+ )
+}
diff --git a/crates/integration-tests/src/shielder/calls/domain_separator.rs b/crates/integration-tests/src/shielder/calls/domain_separator.rs
new file mode 100644
index 00000000..3ef0b40c
--- /dev/null
+++ b/crates/integration-tests/src/shielder/calls/domain_separator.rs
@@ -0,0 +1,27 @@
+use alloy_primitives::U256;
+use rstest::rstest;
+use shielder_rust_sdk::permit2::get_domain_separator;
+
+use crate::{
+ permit2,
+ shielder::deploy::{deployment, Deployment},
+};
+
+#[rstest]
+fn domain_separator(mut deployment: Deployment) {
+ let expected = deployment
+ .evm
+ .call(
+ deployment.contract_suite.permit2,
+ permit2::domain_separator_calldata(),
+ None,
+ None,
+ )
+ .expect("Permit2 DOMAIN_SEPARATOR call failed")
+ .output;
+
+ assert_eq!(
+ get_domain_separator(U256::from(1), deployment.contract_suite.permit2).to_vec(),
+ expected
+ );
+}
diff --git a/crates/integration-tests/src/shielder/calls/mod.rs b/crates/integration-tests/src/shielder/calls/mod.rs
new file mode 100644
index 00000000..7cedc55c
--- /dev/null
+++ b/crates/integration-tests/src/shielder/calls/mod.rs
@@ -0,0 +1,4 @@
+pub mod deposit_native;
+pub mod domain_separator;
+pub mod new_account_native;
+pub mod withdraw_native;
diff --git a/crates/integration-tests/src/shielder/calls/new_account_native.rs b/crates/integration-tests/src/shielder/calls/new_account_native.rs
new file mode 100644
index 00000000..d718e431
--- /dev/null
+++ b/crates/integration-tests/src/shielder/calls/new_account_native.rs
@@ -0,0 +1,177 @@
+use std::assert_matches::assert_matches;
+
+use alloy_primitives::{TxHash, U256};
+use rstest::rstest;
+use shielder_rust_sdk::{
+ account::{call_data::NewAccountCallType, ShielderAccount},
+ contract::ShielderContract::{
+ newAccountNativeCall, NewAccountNative, ShielderContractErrors, ShielderContractEvents,
+ },
+};
+
+use crate::shielder::{
+ actor_balance_decreased_by, deployment, invoke_shielder_call,
+ limits::{get_deposit_limit, set_deposit_limit},
+ CallResult, Deployment,
+};
+
+pub fn prepare_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ amount: U256,
+) -> newAccountNativeCall {
+ let (params, pk) = deployment.new_account_native_proving_params.clone();
+ shielder_account.prepare_call::(¶ms, &pk, amount, &())
+}
+
+pub fn invoke_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ amount: U256,
+ calldata: &newAccountNativeCall,
+) -> CallResult {
+ let call_result = invoke_shielder_call(deployment, calldata, Some(amount));
+
+ match call_result {
+ Ok(event) => {
+ shielder_account.register_action((TxHash::default(), event.clone()));
+ Ok(event)
+ }
+ Err(_) => call_result,
+ }
+}
+
+pub fn create_account_and_call(
+ deployment: &mut Deployment,
+ id: U256,
+ initial_amount: U256,
+) -> Result {
+ let mut shielder_account = ShielderAccount::new(id);
+
+ let calldata = prepare_call(deployment, &mut shielder_account, initial_amount);
+ let result = invoke_call(deployment, &mut shielder_account, initial_amount, &calldata);
+
+ match result {
+ Ok(_) => Ok(shielder_account),
+ Err(e) => Err(e),
+ }
+}
+
+#[rstest]
+fn succeeds(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+ let amount = U256::from(10);
+ let calldata = prepare_call(&mut deployment, &mut shielder_account, amount);
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_eq!(
+ result,
+ Ok(ShielderContractEvents::NewAccountNative(NewAccountNative {
+ idHash: calldata.idHash,
+ amount,
+ newNote: calldata.newNote,
+ newNoteIndex: U256::ZERO,
+ }))
+ );
+ assert!(actor_balance_decreased_by(&deployment, amount));
+ assert_eq!(shielder_account.shielded_amount, U256::from(amount))
+}
+
+#[rstest]
+fn cannot_use_same_id_twice(mut deployment: Deployment) {
+ assert!(create_account_and_call(&mut deployment, U256::from(1), U256::from(10)).is_ok());
+
+ let result = create_account_and_call(&mut deployment, U256::from(1), U256::from(10));
+
+ assert_matches!(result, Err(ShielderContractErrors::DuplicatedNullifier(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(10)))
+}
+
+#[rstest]
+fn can_consume_entire_contract_balance_limit(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+ let amount = U256::from((1u128 << 112) - 1);
+ let calldata = prepare_call(&mut deployment, &mut shielder_account, amount);
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert!(result.is_ok());
+ assert_matches!(result.unwrap(), ShielderContractEvents::NewAccountNative(_));
+ assert!(actor_balance_decreased_by(&deployment, amount))
+}
+
+#[rstest]
+fn fails_if_contract_balance_limit_reached(mut deployment: Deployment) {
+ let amount_1 = U256::from((1u128 << 112) - 1);
+ assert!(create_account_and_call(&mut deployment, U256::from(1), amount_1).is_ok());
+
+ let amount_2 = U256::from(1);
+ let result_2 = create_account_and_call(&mut deployment, U256::from(2), amount_2);
+
+ assert_matches!(
+ result_2,
+ Err(ShielderContractErrors::ContractBalanceLimitReached(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, amount_1))
+}
+
+#[rstest]
+fn correctly_handles_max_u256_value(mut deployment: Deployment) {
+ let result = create_account_and_call(&mut deployment, U256::from(1), U256::MAX);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::ContractBalanceLimitReached(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::ZERO))
+}
+
+#[rstest]
+fn fails_if_proof_incorrect(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+ let amount = U256::from(10);
+ let mut calldata = prepare_call(&mut deployment, &mut shielder_account, amount);
+ calldata.idHash = calldata.idHash.wrapping_add(U256::from(1));
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::NewAccountVerificationFailed(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::ZERO))
+}
+
+#[rstest]
+fn fails_if_over_deposit_limit(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+ let amount = U256::from(101);
+ let calldata = prepare_call(&mut deployment, &mut shielder_account, amount);
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert!(result.is_ok());
+
+ let old_limit = get_deposit_limit(&mut deployment);
+
+ assert_eq!(old_limit, U256::MAX);
+
+ let new_limit = U256::from(100);
+ set_deposit_limit(&mut deployment, new_limit);
+
+ let returned_new_limit = get_deposit_limit(&mut deployment);
+
+ assert_eq!(returned_new_limit, new_limit);
+
+ let mut shielder_account = ShielderAccount::default();
+ let amount = U256::from(101);
+ let calldata = prepare_call(&mut deployment, &mut shielder_account, amount);
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::AmountOverDepositLimit(_))
+ )
+}
diff --git a/crates/integration-tests/src/shielder/calls/withdraw_native.rs b/crates/integration-tests/src/shielder/calls/withdraw_native.rs
new file mode 100644
index 00000000..713c34a5
--- /dev/null
+++ b/crates/integration-tests/src/shielder/calls/withdraw_native.rs
@@ -0,0 +1,361 @@
+use std::{assert_matches::assert_matches, str::FromStr};
+
+use alloy_primitives::{Address, Bytes, TxHash, U256};
+use rstest::rstest;
+use shielder_rust_sdk::{
+ account::{
+ call_data::{MerkleProof, WithdrawCallType, WithdrawExtra},
+ ShielderAccount,
+ },
+ contract::ShielderContract::{
+ withdrawNativeCall, ShielderContractErrors, ShielderContractEvents, WithdrawNative,
+ },
+ version::ContractVersion,
+};
+
+use crate::shielder::{
+ actor_balance_decreased_by,
+ calls::{deposit_native, new_account_native},
+ deploy::{deployment, Deployment, RECIPIENT_ADDRESS, RELAYER_ADDRESS, REVERTING_ADDRESS},
+ destination_balances_unchanged, invoke_shielder_call,
+ merkle::get_merkle_args,
+ recipient_balance_increased_by, relayer_balance_increased_by, CallResult,
+};
+
+struct PrepareCallArgs {
+ amount: U256,
+ withdraw_address: Address,
+ relayer_address: Address,
+ relayer_fee: U256,
+}
+
+fn prepare_args(amount: U256, relayer_fee: U256) -> PrepareCallArgs {
+ PrepareCallArgs {
+ amount,
+ withdraw_address: Address::from_str(RECIPIENT_ADDRESS).unwrap(),
+ relayer_address: Address::from_str(RELAYER_ADDRESS).unwrap(),
+ relayer_fee,
+ }
+}
+
+fn prepare_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ args: PrepareCallArgs,
+) -> (withdrawNativeCall, U256) {
+ let note_index = shielder_account
+ .current_leaf_index()
+ .expect("No leaf index");
+
+ let (params, pk) = deployment.withdraw_native_proving_params.clone();
+ let (merkle_root, merkle_path) = get_merkle_args(
+ deployment.contract_suite.shielder,
+ note_index,
+ &mut deployment.evm,
+ );
+
+ let calldata = shielder_account.prepare_call::(
+ ¶ms,
+ &pk,
+ U256::from(args.amount),
+ &WithdrawExtra {
+ merkle_proof: MerkleProof {
+ root: merkle_root,
+ path: merkle_path,
+ },
+ to: args.withdraw_address,
+ relayer_address: args.relayer_address,
+ relayer_fee: args.relayer_fee,
+ contract_version: ContractVersion {
+ note_version: 0,
+ circuit_version: 0,
+ patch_version: 1,
+ },
+ },
+ );
+
+ (calldata, note_index)
+}
+
+fn invoke_call(
+ deployment: &mut Deployment,
+ shielder_account: &mut ShielderAccount,
+ calldata: &withdrawNativeCall,
+) -> CallResult {
+ let call_result = invoke_shielder_call(deployment, calldata, None);
+
+ match call_result {
+ Ok(event) => {
+ shielder_account.register_action((TxHash::default(), event.clone()));
+ Ok(event)
+ }
+ Err(_) => call_result,
+ }
+}
+
+#[rstest]
+fn succeeds(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (withdraw_calldata, withdraw_note_index) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(5), U256::from(1)),
+ );
+ let withdraw_result = invoke_call(&mut deployment, &mut shielder_account, &withdraw_calldata);
+
+ assert_eq!(
+ withdraw_result,
+ Ok(ShielderContractEvents::WithdrawNative(WithdrawNative {
+ idHiding: withdraw_calldata.idHiding,
+ amount: U256::from(5),
+ withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(),
+ newNote: withdraw_calldata.newNote,
+ relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(),
+ newNoteIndex: withdraw_note_index.saturating_add(U256::from(1)),
+ fee: U256::from(1),
+ }))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(recipient_balance_increased_by(&deployment, U256::from(4)));
+ assert!(relayer_balance_increased_by(&deployment, U256::from(1)));
+ assert_eq!(shielder_account.shielded_amount, U256::from(15))
+}
+
+#[rstest]
+fn succeeds_after_deposit(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let deposit_amount = U256::from(10);
+ let (deposit_calldata, _) =
+ deposit_native::prepare_call(&mut deployment, &mut shielder_account, deposit_amount);
+ deposit_native::invoke_call(
+ &mut deployment,
+ &mut shielder_account,
+ deposit_amount,
+ &deposit_calldata,
+ )
+ .unwrap();
+
+ let (withdraw_calldata, withdraw_note_index) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(5), U256::from(1)),
+ );
+ let withdraw_result = invoke_call(&mut deployment, &mut shielder_account, &withdraw_calldata);
+
+ assert_eq!(
+ withdraw_result,
+ Ok(ShielderContractEvents::WithdrawNative(WithdrawNative {
+ idHiding: withdraw_calldata.idHiding,
+ amount: U256::from(5),
+ withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(),
+ newNote: withdraw_calldata.newNote,
+ relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(),
+ newNoteIndex: withdraw_note_index.saturating_add(U256::from(1)),
+ fee: U256::from(1),
+ }))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(30)));
+ assert!(recipient_balance_increased_by(&deployment, U256::from(4)));
+ assert!(relayer_balance_increased_by(&deployment, U256::from(1)));
+ assert_eq!(shielder_account.shielded_amount, U256::from(25))
+}
+
+#[rstest]
+fn fails_if_proof_incorrect(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (mut calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(5), U256::from(1)),
+ );
+ calldata.newNote = calldata.newNote.wrapping_add(U256::from(1));
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::WithdrawVerificationFailed(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn rejects_value_zero(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(0), U256::from(1)),
+ );
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::ZeroAmount(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn fails_if_fee_higher_than_amount(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(3), U256::from(3)),
+ );
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::FeeHigherThanAmount(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn accepts_max_amount(mut deployment: Deployment) {
+ let mut shielder_account = new_account_native::create_account_and_call(
+ &mut deployment,
+ U256::from(1),
+ U256::from((1u128 << 112) - 1),
+ )
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from((1u128 << 112) - 1), U256::from(1)),
+ );
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert!(result.is_ok());
+ assert!(actor_balance_decreased_by(
+ &deployment,
+ U256::from((1u128 << 112) - 1)
+ ));
+ assert!(recipient_balance_increased_by(
+ &deployment,
+ U256::from((1u128 << 112) - 2)
+ ));
+ assert!(relayer_balance_increased_by(&deployment, U256::from(1)))
+}
+
+#[rstest]
+fn rejects_too_high_amount(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (mut calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(2), U256::from(1)),
+ );
+ calldata.amount = U256::from(1u128 << 112);
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::AmountTooHigh(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn fails_if_merkle_root_does_not_exist(mut deployment: Deployment) {
+ let mut shielder_account = ShielderAccount::default();
+
+ let calldata = withdrawNativeCall {
+ idHiding: U256::ZERO,
+ withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(),
+ relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(),
+ relayerFee: U256::ZERO,
+ amount: U256::from(10),
+ merkleRoot: U256::ZERO,
+ oldNullifierHash: U256::ZERO,
+ newNote: U256::ZERO,
+ proof: Bytes::from(vec![]),
+ };
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(
+ result,
+ Err(ShielderContractErrors::MerkleRootDoesNotExist(_))
+ );
+ assert!(actor_balance_decreased_by(&deployment, U256::from(0)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn cannot_use_same_note_twice(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ prepare_args(U256::from(5), U256::from(1)),
+ );
+ assert!(invoke_call(&mut deployment, &mut shielder_account, &calldata).is_ok());
+
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::DuplicatedNullifier(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(recipient_balance_increased_by(&deployment, U256::from(4)));
+ assert!(relayer_balance_increased_by(&deployment, U256::from(1)))
+}
+
+#[rstest]
+fn handles_withdraw_transfer_failure(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ PrepareCallArgs {
+ withdraw_address: Address::from_str(REVERTING_ADDRESS).unwrap(),
+ ..prepare_args(U256::from(5), U256::from(1))
+ },
+ );
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::NativeTransferFailed(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
+
+#[rstest]
+fn handles_fee_transfer_failure(mut deployment: Deployment) {
+ let mut shielder_account =
+ new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20))
+ .unwrap();
+
+ let (calldata, _) = prepare_call(
+ &mut deployment,
+ &mut shielder_account,
+ PrepareCallArgs {
+ relayer_address: Address::from_str(REVERTING_ADDRESS).unwrap(),
+ ..prepare_args(U256::from(5), U256::from(1))
+ },
+ );
+ let result = invoke_call(&mut deployment, &mut shielder_account, &calldata);
+
+ assert_matches!(result, Err(ShielderContractErrors::NativeTransferFailed(_)));
+ assert!(actor_balance_decreased_by(&deployment, U256::from(20)));
+ assert!(destination_balances_unchanged(&deployment))
+}
diff --git a/crates/integration-tests/src/shielder/deploy.rs b/crates/integration-tests/src/shielder/deploy.rs
new file mode 100644
index 00000000..8c00a49a
--- /dev/null
+++ b/crates/integration-tests/src/shielder/deploy.rs
@@ -0,0 +1,246 @@
+use std::str::FromStr;
+
+use alloy_primitives::{keccak256, Address, Bytes, U256};
+use alloy_sol_types::{SolCall, SolConstructor};
+use evm_utils::{
+ compilation::source_to_bytecode,
+ revm_primitives::{AccountInfo, Bytecode},
+ EvmRunner,
+};
+use rstest::{fixture, rstest};
+use shielder_rust_sdk::contract::ShielderContract::initializeCall;
+
+use crate::{
+ deploy_contract,
+ permit2::PERMIT2_BYTECODE,
+ proving_utils::{
+ deposit_native_proving_params, new_account_native_proving_params,
+ withdraw_native_proving_params, ProvingParams,
+ },
+ read_contract,
+ shielder::{
+ erc1967proxy::{self, ERC_1967_PROXY_BYTECODE},
+ unpause_shielder,
+ },
+ token,
+ verifier::{deploy_verifiers_and_keys, VerificationContracts},
+};
+
+/// The address of the deployer account.
+///
+/// This is one of the default accounts in the Anvil testnet.
+pub const DEPLOYER_ADDRESS: &str = "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
+pub const DEPLOYER_INITIAL_BALANCE: U256 = U256::MAX;
+
+/// The address of the actor account.
+///
+/// This is one of the default accounts in the Anvil testnet.
+pub const ACTOR_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79C8";
+pub const ACTOR_INITIAL_BALANCE: U256 = U256::MAX;
+
+/// The private key of the actor account.
+pub const ACTOR_PRIVATE_KEY: &str =
+ "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
+
+pub const RECIPIENT_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79C9";
+pub const RECIPIENT_INITIAL_BALANCE: U256 = U256::ZERO;
+
+pub const RELAYER_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79CA";
+pub const RELAYER_INITIAL_BALANCE: U256 = U256::ZERO;
+
+// Will always revert when receiving funds.
+pub const REVERTING_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79CB";
+pub const REVERTING_ADDRESS_INITIAL_BALANCE: U256 = U256::ZERO;
+pub const REVERTING_BYTECODE: [u8; 4] = [0x60, 0x00, 0x80, 0xfd]; // PUSH1 0x00 DUP1 REVERT
+
+pub const INITIAL_DEPOSIT_LIMIT: U256 = U256::MAX;
+
+/// Contains full deployment addresses.
+pub struct ShielderContractSuite {
+ pub permit2: Address,
+ pub shielder: Address,
+ pub token: Address,
+}
+
+pub fn prepare_account(
+ evm: &mut EvmRunner,
+ address: &str,
+ balance: U256,
+ code: Option,
+) -> Address {
+ let caller = Address::from_str(address).unwrap();
+ evm.db.insert_account_info(
+ caller,
+ AccountInfo {
+ nonce: 0_u64,
+ balance,
+ code_hash: keccak256(Bytes::new()),
+ code,
+ },
+ );
+ caller
+}
+
+/// Solc leaves this placeholder for a Poseidon2 contract address.
+const POSEIDON2_LIB_PLACEHOLDER: &str = "__$fa7e1b6d9a16949b5fb8159594c1e0b34c$__";
+
+pub struct Deployment {
+ pub evm: EvmRunner,
+ pub contract_suite: ShielderContractSuite,
+ pub new_account_native_proving_params: ProvingParams,
+ pub deposit_native_proving_params: ProvingParams,
+ pub withdraw_native_proving_params: ProvingParams,
+}
+
+/// Deploy whole Shielder suite.
+#[fixture]
+pub fn deployment(
+ new_account_native_proving_params: &ProvingParams,
+ deposit_native_proving_params: &ProvingParams,
+ withdraw_native_proving_params: &ProvingParams,
+) -> Deployment {
+ let mut evm = EvmRunner::aleph_evm();
+ let owner = prepare_account(&mut evm, DEPLOYER_ADDRESS, DEPLOYER_INITIAL_BALANCE, None);
+ let actor = prepare_account(&mut evm, ACTOR_ADDRESS, ACTOR_INITIAL_BALANCE, None);
+ prepare_account(&mut evm, RECIPIENT_ADDRESS, RECIPIENT_INITIAL_BALANCE, None);
+ prepare_account(&mut evm, RELAYER_ADDRESS, RELAYER_INITIAL_BALANCE, None);
+ let reverting_bytecode = Bytecode::new_raw(Bytes::from_static(&REVERTING_BYTECODE));
+ prepare_account(
+ &mut evm,
+ REVERTING_ADDRESS,
+ REVERTING_ADDRESS_INITIAL_BALANCE,
+ Some(reverting_bytecode),
+ );
+
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+ let token = deploy_token(&mut evm, owner);
+ let permit2 = deploy_permit2(&mut evm, owner);
+ let shielder_address = deploy_shielder_contract(verification_contracts, &mut evm, owner);
+ unpause_shielder(shielder_address, &mut evm);
+ instrument_token(&mut evm, owner, actor, token, permit2);
+
+ Deployment {
+ evm,
+ contract_suite: ShielderContractSuite {
+ token,
+ permit2,
+ shielder: shielder_address,
+ },
+ new_account_native_proving_params: new_account_native_proving_params.clone(),
+ deposit_native_proving_params: deposit_native_proving_params.clone(),
+ withdraw_native_proving_params: withdraw_native_proving_params.clone(),
+ }
+}
+
+/// Deploy ERC20 token contract
+fn deploy_token(evm: &mut EvmRunner, caller: Address) -> Address {
+ let solidity_code = read_contract("Token.sol");
+ let compiled_bytecode = source_to_bytecode(solidity_code, "Token", true);
+
+ let constructor_calldata = token::constructor_calldata(U256::from(1000000));
+ let calldata = [compiled_bytecode, constructor_calldata].concat();
+
+ evm.create(calldata, Some(caller))
+ .expect("Failed to deploy the Token contract")
+}
+
+/// Performs basic instrumentation:
+/// - Transfer an initial amount of ERC20 to the actor account
+/// - Approve Permit2 as spender
+fn instrument_token(
+ evm: &mut EvmRunner,
+ owner: Address,
+ actor: Address,
+ token: Address,
+ permit2: Address,
+) {
+ evm.call(
+ token,
+ token::transfer_calldata(actor, U256::from(100000)),
+ Some(owner),
+ None,
+ )
+ .expect("ERC20 transfer call failed");
+
+ evm.call(
+ token,
+ token::approve_calldata(permit2, U256::MAX),
+ Some(actor),
+ None,
+ )
+ .expect("ERC20 approve call failed");
+}
+
+/// deploy Permit2 contract from a pre-compiled bytecode.
+fn deploy_permit2(evm: &mut EvmRunner, caller: Address) -> Address {
+ let bytecode = hex::decode(PERMIT2_BYTECODE).expect("Failed to decode permit2 bytecode");
+ evm.create(bytecode, Some(caller))
+ .expect("Failed to deploy Shielder implementation contract")
+}
+
+/// Deploys the Shielder implementation contract.
+///
+/// This requires more steps than deploying a regular contract because Solc leaves placeholders
+/// in the bytecode, which has to be replaced with a deployed Poseidon2 contract address.
+fn deploy_shielder_implementation(evm: &mut EvmRunner) -> Address {
+ // 1. Compile the Shielder implementation contract. It will contain placeholders.
+ let solidity_code = read_contract("Shielder.sol");
+ let implementation_bytecode = source_to_bytecode(solidity_code, "Shielder", false);
+
+ // 2. Compile and deploy auxiliary contracts.
+ let poseidon2_address =
+ deploy_contract("Poseidon2T8Assembly.sol", "Poseidon2T8Assembly", evm).to_string();
+
+ // 3. Manipulate the Shielder implementation bytecode to replace the placeholders with the
+ // corresponding contract addresses.
+ let implementation_bytecode = String::from_utf8(implementation_bytecode).unwrap();
+ let with_poseidon2 = implementation_bytecode.replace(
+ POSEIDON2_LIB_PLACEHOLDER,
+ poseidon2_address.strip_prefix("0x").unwrap(),
+ );
+ let ready_bytecode = hex::decode(with_poseidon2).unwrap();
+
+ // 4. Finally, deploy the Shielder implementation contract.
+ evm.create(ready_bytecode, None)
+ .expect("Failed to deploy Shielder implementation contract")
+}
+
+/// Deploy Shielder contract using ERC 1967 proxy.
+pub fn deploy_shielder_contract(
+ verification_contracts: VerificationContracts,
+ evm: &mut EvmRunner,
+ owner: Address,
+) -> Address {
+ let implementation_address = deploy_shielder_implementation(evm);
+ let initialization_data = initializeCall {
+ initialOwner: owner,
+ _newAccountVerifier: verification_contracts.new_account_verifier,
+ _depositVerifier: verification_contracts.deposit_verifier,
+ _withdrawVerifier: verification_contracts.withdraw_verifier,
+ _newAccountVerifyingKey: verification_contracts.new_account_vk,
+ _depositVerifyingKey: verification_contracts.deposit_vk,
+ _withdrawVerifyingKey: verification_contracts.withdraw_vk,
+ _depositLimit: INITIAL_DEPOSIT_LIMIT,
+ }
+ .abi_encode();
+
+ let proxy_bytecode =
+ hex::decode(ERC_1967_PROXY_BYTECODE).expect("Failed to decode proxy bytecode");
+ let proxy_calldata = [
+ proxy_bytecode,
+ erc1967proxy::constructorCall {
+ implementation: implementation_address,
+ _data: Bytes::from(initialization_data),
+ }
+ .abi_encode(),
+ ]
+ .concat();
+
+ evm.create(proxy_calldata, Some(owner))
+ .expect("Failed to deploy Shielder contract through a proxy")
+}
+
+#[rstest]
+fn deploy_shielder_suite(_deployment: Deployment) {
+ // Deployment successful.
+}
diff --git a/crates/integration-tests/src/shielder/erc1967proxy.rs b/crates/integration-tests/src/shielder/erc1967proxy.rs
new file mode 100644
index 00000000..787fc95d
--- /dev/null
+++ b/crates/integration-tests/src/shielder/erc1967proxy.rs
@@ -0,0 +1,8 @@
+use alloy_sol_types::sol;
+
+pub const ERC_1967_PROXY_BYTECODE: &str =
+ "608060405261028a803803806100148161017e565b92833981019060408183031261017a578051906001600160a01b0382169081830361017a576020810151906001600160401b03821161017a570183601f8201121561017a5780519061006d610068836101b7565b61017e565b948286526020838301011161017a575f5b82811061016557505060205f9185010152813b15610153577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a281511561013c575f8083602061012495519101845af43d15610134573d91610115610068846101b7565b9283523d5f602085013e6101d2565b505b604051605990816102318239f35b6060916101d2565b505034156101265763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f5260045260245ffd5b8060208092840101518282890101520161007e565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101a357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101a357601f01601f191660200190565b906101f657508051156101e757805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610227575b610207575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101ff56fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea164736f6c634300081a000a";
+
+sol! {
+ constructor(address implementation, bytes memory _data) payable;
+}
diff --git a/crates/integration-tests/src/shielder/limits.rs b/crates/integration-tests/src/shielder/limits.rs
new file mode 100644
index 00000000..61a37f59
--- /dev/null
+++ b/crates/integration-tests/src/shielder/limits.rs
@@ -0,0 +1,35 @@
+use std::str::FromStr;
+
+use alloy_primitives::U256;
+use alloy_sol_types::{SolCall, SolValue};
+use shielder_rust_sdk::contract::ShielderContract::{depositLimitCall, setDepositLimitCall};
+
+use super::deploy::DEPLOYER_ADDRESS;
+use crate::{shielder::deploy::Deployment, Address};
+
+pub fn set_deposit_limit(deployment: &mut Deployment, limit: U256) {
+ let calldata = setDepositLimitCall {
+ _depositLimit: limit,
+ }
+ .abi_encode();
+
+ deployment
+ .evm
+ .call(
+ deployment.contract_suite.shielder,
+ calldata,
+ Some(Address::from_str(DEPLOYER_ADDRESS).unwrap()),
+ None,
+ )
+ .expect("Call failed");
+}
+
+pub fn get_deposit_limit(deployment: &mut Deployment) -> U256 {
+ let calldata = depositLimitCall {}.abi_encode();
+ let encoded_limit = deployment
+ .evm
+ .call(deployment.contract_suite.shielder, calldata, None, None)
+ .expect("Call failed")
+ .output;
+ ::abi_decode(&encoded_limit, true).expect("Decoding failed")
+}
diff --git a/crates/integration-tests/src/shielder/merkle.rs b/crates/integration-tests/src/shielder/merkle.rs
new file mode 100644
index 00000000..ad87513d
--- /dev/null
+++ b/crates/integration-tests/src/shielder/merkle.rs
@@ -0,0 +1,36 @@
+use alloy_primitives::{Address, U256};
+use alloy_sol_types::{SolCall, SolValue};
+use evm_utils::EvmRunner;
+use shielder_circuits::consts::merkle_constants::{ARITY, NOTE_TREE_HEIGHT};
+use shielder_rust_sdk::contract::ShielderContract::getMerklePathCall;
+
+pub fn get_merkle_args(
+ shielder_address: Address,
+ note_index: U256,
+ evm: &mut EvmRunner,
+) -> (U256, [[U256; ARITY]; NOTE_TREE_HEIGHT]) {
+ let calldata = getMerklePathCall { id: note_index }.abi_encode();
+ let result = evm
+ .call(shielder_address, calldata, None, None)
+ .expect("Call failed")
+ .output;
+ let decoded = >::abi_decode(&result, true).expect("Decoding failed");
+ reorganize_merkle_path(decoded)
+}
+
+fn reorganize_merkle_path(merkle_path: Vec) -> (U256, [[U256; ARITY]; NOTE_TREE_HEIGHT]) {
+ assert_eq!(merkle_path.len(), ARITY * NOTE_TREE_HEIGHT + 1);
+
+ let root = *merkle_path.last().expect("Empty merkle path");
+
+ let mut result = [[U256::ZERO; ARITY]; NOTE_TREE_HEIGHT];
+ for (i, element) in merkle_path
+ .into_iter()
+ .enumerate()
+ .take(ARITY * NOTE_TREE_HEIGHT)
+ {
+ result[i / ARITY][i % ARITY] = element;
+ }
+
+ (root, result)
+}
diff --git a/crates/integration-tests/src/shielder/mod.rs b/crates/integration-tests/src/shielder/mod.rs
new file mode 100644
index 00000000..96b69da8
--- /dev/null
+++ b/crates/integration-tests/src/shielder/mod.rs
@@ -0,0 +1,83 @@
+use std::str::FromStr;
+
+use alloy_primitives::{Address, U256};
+use alloy_sol_types::{SolCall, SolEventInterface, SolInterface};
+use deploy::{
+ deployment, Deployment, ACTOR_ADDRESS, ACTOR_INITIAL_BALANCE, DEPLOYER_ADDRESS,
+ RECIPIENT_ADDRESS, RECIPIENT_INITIAL_BALANCE, RELAYER_ADDRESS, RELAYER_INITIAL_BALANCE,
+};
+use evm_utils::{EvmRunner, EvmRunnerError};
+use shielder_rust_sdk::contract::ShielderContract::{
+ unpauseCall, ShielderContractErrors, ShielderContractEvents,
+};
+
+mod address_conversion;
+mod calls;
+mod deploy;
+mod erc1967proxy;
+mod limits;
+mod merkle;
+
+fn unpause_shielder(shielder: Address, evm: &mut EvmRunner) {
+ evm.call(
+ shielder,
+ unpauseCall {}.abi_encode(),
+ Some(Address::from_str(DEPLOYER_ADDRESS).unwrap()),
+ None,
+ )
+ .expect("Call failed");
+}
+
+type CallResult = Result;
+
+fn invoke_shielder_call(
+ deployment: &mut Deployment,
+ calldata: &impl SolCall,
+ value: Option,
+) -> CallResult {
+ let logs = deployment
+ .evm
+ .call(
+ deployment.contract_suite.shielder,
+ calldata.abi_encode(),
+ Some(Address::from_str(ACTOR_ADDRESS).unwrap()),
+ value,
+ )
+ .map_err(|e| match e {
+ EvmRunnerError::Revert(e) => {
+ ShielderContractErrors::abi_decode(e.output().unwrap(), true).unwrap()
+ }
+ _ => panic!("Expected EvmRunnerError::Revert"),
+ })?
+ .logs;
+
+ assert_eq!(logs.len(), 1);
+ let event = ShielderContractEvents::decode_log(&logs[0], true).expect("Decoding event failed");
+ assert_eq!(event.address, deployment.contract_suite.shielder);
+
+ Ok(event.data)
+}
+
+fn get_balance(deployment: &Deployment, address: &str) -> U256 {
+ deployment
+ .evm
+ .get_balance(Address::from_str(address).unwrap())
+ .unwrap()
+}
+
+fn actor_balance_decreased_by(deployment: &Deployment, amount: U256) -> bool {
+ get_balance(&deployment, ACTOR_ADDRESS) == ACTOR_INITIAL_BALANCE - amount
+}
+
+fn recipient_balance_increased_by(deployment: &Deployment, amount: U256) -> bool {
+ get_balance(&deployment, RECIPIENT_ADDRESS) == RECIPIENT_INITIAL_BALANCE + amount
+}
+
+fn relayer_balance_increased_by(deployment: &Deployment, amount: U256) -> bool {
+ get_balance(&deployment, RELAYER_ADDRESS) == RELAYER_INITIAL_BALANCE + amount
+}
+
+fn destination_balances_unchanged(deployment: &Deployment) -> bool {
+ recipient_balance_increased_by(deployment, U256::ZERO)
+ && relayer_balance_increased_by(deployment, U256::ZERO)
+}
diff --git a/crates/integration-tests/src/token.rs b/crates/integration-tests/src/token.rs
new file mode 100644
index 00000000..6546ebdf
--- /dev/null
+++ b/crates/integration-tests/src/token.rs
@@ -0,0 +1,25 @@
+use alloy_primitives::{Address, U256};
+use alloy_sol_types::{sol, SolCall, SolConstructor};
+
+sol! {
+ constructor(uint256 initialSupply);
+
+ function approve(address spender, uint256 value) external returns (bool);
+
+ function transfer(address to, uint256 value) external returns (bool);
+}
+
+pub fn constructor_calldata(initial_supply: U256) -> Vec {
+ constructorCall {
+ initialSupply: initial_supply,
+ }
+ .abi_encode()
+}
+
+pub fn approve_calldata(spender: Address, value: U256) -> Vec {
+ approveCall { spender, value }.abi_encode()
+}
+
+pub fn transfer_calldata(to: Address, value: U256) -> Vec {
+ transferCall { to, value }.abi_encode()
+}
diff --git a/crates/integration-tests/src/verifier.rs b/crates/integration-tests/src/verifier.rs
new file mode 100644
index 00000000..c4595871
--- /dev/null
+++ b/crates/integration-tests/src/verifier.rs
@@ -0,0 +1,161 @@
+use alloy_primitives::Address;
+use alloy_sol_types::SolValue;
+use evm_utils::EvmRunner;
+use halo2_proofs::halo2curves::bn256::Fr;
+use halo2_solidity_verifier::verifier_contract;
+use shielder_circuits::{
+ consts::RANGE_PROOF_CHUNK_SIZE, deposit::DepositProverKnowledge,
+ new_account::NewAccountProverKnowledge, withdraw::WithdrawProverKnowledge, F,
+};
+
+use crate::{deploy_contract, proving_utils};
+
+const VERIFIER_CONTRACT_NAME: &str = "Halo2Verifier";
+const VK_CONTRACT_NAME: &str = "Halo2VerifyingKey";
+
+#[derive(Copy, Clone)]
+pub struct VerificationContracts {
+ pub new_account_verifier: Address,
+ pub new_account_vk: Address,
+ pub deposit_verifier: Address,
+ pub deposit_vk: Address,
+ pub withdraw_verifier: Address,
+ pub withdraw_vk: Address,
+}
+
+pub fn deploy_verifiers_and_keys(evm: &mut EvmRunner) -> VerificationContracts {
+ let new_account_verifier =
+ deploy_contract("NewAccountVerifier.sol", VERIFIER_CONTRACT_NAME, evm);
+ let new_account_vk = deploy_contract("NewAccountVerifyingKey.sol", VK_CONTRACT_NAME, evm);
+ let deposit_verifier = deploy_contract("DepositVerifier.sol", VERIFIER_CONTRACT_NAME, evm);
+ let deposit_vk = deploy_contract("DepositVerifyingKey.sol", VK_CONTRACT_NAME, evm);
+ let withdraw_verifier = deploy_contract("WithdrawVerifier.sol", VERIFIER_CONTRACT_NAME, evm);
+ let withdraw_vk = deploy_contract("WithdrawVerifyingKey.sol", VK_CONTRACT_NAME, evm);
+
+ VerificationContracts {
+ new_account_verifier,
+ new_account_vk,
+ deposit_verifier,
+ deposit_vk,
+ withdraw_verifier,
+ withdraw_vk,
+ }
+}
+
+#[test]
+fn deploy_verification_contracts() {
+ deploy_verifiers_and_keys(&mut EvmRunner::aleph_evm());
+}
+
+fn verify_with_contract(
+ proof: Vec,
+ pub_input: Vec,
+ vk_address: Address,
+ verifier_address: Address,
+ evm: &mut EvmRunner,
+) -> bool {
+ let calldata = verifier_contract::encode_calldata(vk_address, &proof, &pub_input);
+ let response = evm
+ .call(verifier_address, calldata, None, None)
+ .expect("Call failed")
+ .output;
+ ::abi_decode(&response, true).expect("Decoding contract response failed")
+}
+
+#[test]
+fn new_account_contract_verification_works() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ let (proof, pub_input) = proving_utils::prepare_proof::>();
+ assert!(verify_with_contract(
+ proof,
+ pub_input,
+ verification_contracts.new_account_vk,
+ verification_contracts.new_account_verifier,
+ &mut evm,
+ ));
+}
+
+#[test]
+fn deposit_contract_verification_works() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ let (proof, pub_input) =
+ proving_utils::prepare_proof::>();
+ assert!(verify_with_contract(
+ proof,
+ pub_input,
+ verification_contracts.deposit_vk,
+ verification_contracts.deposit_verifier,
+ &mut evm,
+ ));
+}
+
+#[test]
+fn withdraw_contract_verification_works() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ let (proof, pub_input) =
+ proving_utils::prepare_proof::>();
+ assert!(verify_with_contract(
+ proof,
+ pub_input,
+ verification_contracts.withdraw_vk,
+ verification_contracts.withdraw_verifier,
+ &mut evm,
+ ));
+}
+
+// Should trigger an early return in `Halo2Verifier`.
+#[test]
+fn fails_on_empty_proof() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ assert!(!verify_with_contract(
+ vec![],
+ vec![],
+ verification_contracts.new_account_vk,
+ verification_contracts.new_account_verifier,
+ &mut evm,
+ ));
+}
+
+// Should trigger a late return in `Halo2Verifier`.
+#[test]
+fn fails_on_proof_with_wrong_input() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ let (proof, mut pub_input) = proving_utils::prepare_proof::>();
+ pub_input[0] += Fr::from(1);
+
+ assert!(!verify_with_contract(
+ proof,
+ pub_input,
+ verification_contracts.new_account_vk,
+ verification_contracts.new_account_verifier,
+ &mut evm,
+ ));
+}
+
+// Should trigger a late return in `Halo2Verifier`.
+#[test]
+fn fails_on_corrupted_proof() {
+ let mut evm = EvmRunner::aleph_evm();
+ let verification_contracts = deploy_verifiers_and_keys(&mut evm);
+
+ let (mut proof, pub_input) = proving_utils::prepare_proof::>();
+ proof[0] = proof[0].wrapping_add(1u8);
+
+ assert!(!verify_with_contract(
+ proof,
+ pub_input,
+ verification_contracts.new_account_vk,
+ verification_contracts.new_account_verifier,
+ &mut evm,
+ ));
+}
diff --git a/crates/shielder-cli/Cargo.toml b/crates/shielder-cli/Cargo.toml
new file mode 100644
index 00000000..dbd12385
--- /dev/null
+++ b/crates/shielder-cli/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "shielder-cli"
+version = "0.1.0"
+readme = "README.md"
+description = "CLI for interacting with the zkOS Shielder contract"
+
+edition.workspace = true
+authors.workspace = true
+homepage.workspace = true
+license.workspace = true
+categories.workspace = true
+repository.workspace = true
+
+[dependencies]
+alloy-contract = { workspace = true }
+alloy-eips = { workspace = true }
+alloy-network = { workspace = true }
+alloy-primitives = { workspace = true }
+alloy-provider = { workspace = true }
+alloy-rpc-types-eth = { workspace = true }
+alloy-signer-local = { workspace = true }
+alloy-sol-types = { workspace = true }
+anyhow = { workspace = true, default-features = true }
+clap = { workspace = true, features = ["derive"] }
+inquire = { workspace = true }
+rand = { workspace = true }
+reqwest = { workspace = true }
+serde = { workspace = true, features = ["derive"] }
+serde_json = { workspace = true }
+shellexpand = { workspace = true }
+tokio = { workspace = true, features = ["rt-multi-thread"] }
+tracing = { workspace = true }
+tracing-subscriber = { workspace = true, features = ["fmt", "json", "env-filter"] }
+
+content-encryption = { workspace = true, features = ["std"] }
+shielder-circuits = { workspace = true }
+shielder-relayer = { workspace = true }
+shielder-rust-sdk = { workspace = true, features = ["account", "contract", "conversion", "powers_of_tau"] }
diff --git a/crates/shielder-cli/Makefile b/crates/shielder-cli/Makefile
new file mode 100644
index 00000000..223ad733
--- /dev/null
+++ b/crates/shielder-cli/Makefile
@@ -0,0 +1,15 @@
+.PHONY: build
+build: ## Build the project
+ @cargo build --release
+
+.PHONY: test
+test: ## Run tests
+ @cargo test --release
+
+.PHONY: lint
+lint: ## Run clippy and fmt
+ @cargo clippy --release -- -D warnings
+ @cargo +nightly fmt --all
+
+help: ## Displays this help
+ @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
diff --git a/crates/shielder-cli/src/app_state.rs b/crates/shielder-cli/src/app_state.rs
new file mode 100644
index 00000000..4e61b553
--- /dev/null
+++ b/crates/shielder-cli/src/app_state.rs
@@ -0,0 +1,107 @@
+use std::str::FromStr;
+
+use alloy_primitives::{Address, U256};
+use alloy_provider::Provider;
+use alloy_signer_local::PrivateKeySigner;
+use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
+use shielder_rust_sdk::{
+ account::ShielderAccount,
+ contract::{
+ providers::create_simple_provider, ConnectionPolicy, ShielderContractError, ShielderUser,
+ },
+};
+use tracing::{debug, warn};
+
+/// The URL of the relayer RPC.
+#[derive(Clone, Eq, PartialEq, Debug, Default, Deserialize, Serialize)]
+pub struct RelayerRpcUrl {
+ base_url: String,
+}
+
+impl RelayerRpcUrl {
+ pub fn new(base_url: String) -> Self {
+ Self { base_url }
+ }
+
+ pub fn healthcheck_url(&self) -> String {
+ format!("{}/health", self.base_url)
+ }
+
+ pub fn relay_url(&self) -> String {
+ format!("{}/relay", self.base_url)
+ }
+
+ pub async fn check_connection(&self) -> anyhow::Result<()> {
+ let response = reqwest::get(self.healthcheck_url()).await?;
+ if response.status().is_success() {
+ debug!("Relayer healthcheck succeeded.");
+ Ok(())
+ } else {
+ warn!("Relayer healthcheck failed.");
+ Err(anyhow!("Relayer healthcheck failed."))
+ }
+ }
+}
+
+/// Application info that is kept locally.
+///
+/// WARNING: You SHOULD NOT use `Self::Default` in production, as this will set the seed to
+/// zero, which is insecure and might get in conflict with other accounts (similarly set up)
+#[derive(Clone, Eq, PartialEq, Debug, Default, Deserialize, Serialize)]
+pub struct AppState {
+ pub account: ShielderAccount,
+ pub node_rpc_url: String,
+ pub contract_address: Address,
+ pub relayer_rpc_url: RelayerRpcUrl,
+ pub relayer_address: Address,
+ pub signing_key: String,
+}
+
+impl AppState {
+ /// Create a new `AppState` with a given signing key, which will be used for both signing
+ /// on-chain transactions and as a shielded account seed.
+ ///
+ /// Note: You SHOULD prefer using `Self::new` instead of `Default::default()`, unless you are
+ /// writing single-actor tests.
+ pub fn new(signing_key: &str) -> Self {
+ let seed = U256::from_str(signing_key).expect("Invalid key format - cannot cast to U256");
+ Self {
+ account: ShielderAccount::new(seed),
+ signing_key: signing_key.into(),
+ ..Default::default()
+ }
+ }
+
+ pub fn display_app_config(&self) -> String {
+ format!(
+ "
+Node address: {}
+Contract address: {}
+Relayer url: {}
+Relayer address: {}
+Depositor signing key: {}",
+ self.node_rpc_url,
+ self.contract_address,
+ self.relayer_rpc_url.relay_url(),
+ self.relayer_address,
+ self.signing_key
+ )
+ }
+
+ pub fn create_shielder_user(&self) -> ShielderUser {
+ let signer = PrivateKeySigner::from_str(&self.signing_key)
+ .expect("Invalid key format - cannot cast to PrivateKeySigner");
+ ShielderUser::new(
+ self.contract_address,
+ ConnectionPolicy::OnDemand {
+ rpc_url: self.node_rpc_url.clone(),
+ signer,
+ },
+ )
+ }
+
+ pub async fn create_simple_provider(&self) -> Result {
+ create_simple_provider(&self.node_rpc_url).await
+ }
+}
diff --git a/crates/shielder-cli/src/config.rs b/crates/shielder-cli/src/config.rs
new file mode 100644
index 00000000..037c04f1
--- /dev/null
+++ b/crates/shielder-cli/src/config.rs
@@ -0,0 +1,155 @@
+use std::path::PathBuf;
+
+use alloy_primitives::Address;
+use anyhow::Result;
+use clap::{Args, Parser, Subcommand, ValueEnum};
+use inquire::Password;
+
+#[derive(Clone, Eq, PartialEq, Debug, Parser)]
+pub struct CliConfig {
+ /// Path to the file containing application state.
+ #[clap(long, default_value = "~/.shielder-state", value_parser = parsing::parse_path)]
+ pub state_file: PathBuf,
+
+ /// Logging configuration.
+ #[clap(short = 'l', value_enum, default_value = "text")]
+ pub logging_format: LoggingFormat,
+
+ /// Password for `state_file` encryption and decryption.
+ ///
+ /// If not provided, will be prompted.
+ #[clap(long)]
+ password: Option,
+
+ /// Do not prompt for a password. Use empty password instead. Only for testing.
+ #[clap(long, default_value = "false")]
+ no_password: bool,
+
+ #[clap(subcommand)]
+ pub command: Command,
+}
+
+impl CliConfig {
+ pub fn password(&self) -> Result {
+ if self.no_password {
+ return Ok("".to_string());
+ }
+ match &self.password {
+ Some(password) => Ok(password.clone()),
+ None => Ok(Password::new("Password (for encrypting local state):")
+ .without_confirmation()
+ .prompt()?),
+ }
+ }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Subcommand)]
+pub enum Command {
+ #[clap(flatten)]
+ StateWrite(StateWriteCommand),
+ #[clap(flatten)]
+ StateRead(StateReadCommand),
+ #[clap(flatten)]
+ ContractInteraction(ContractInteractionCommand),
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Subcommand)]
+pub enum StateWriteCommand {
+ /// Initialize local state using ETH private key for both signing on-chain transactions and
+ /// as the shielded account seed.
+ Initialize {
+ /// Private key of the depositor account.
+ private_key: String,
+ },
+ /// Set RPC address of the node that we will be connecting to.
+ NodeUrl {
+ /// RPC endpoint address of the node to connect to.
+ node: String,
+ },
+ /// Set address of the Shielder contract.
+ ContractAddress {
+ /// Address of the Shielder contract.
+ address: Address,
+ },
+ /// Set relayer URL address.
+ RelayerUrl {
+ /// Address of the relayer.
+ url: String,
+ },
+ /// Set relayer chain address.
+ RelayerAddress {
+ /// Address of the relayer.
+ address: Address,
+ },
+ /// Recover state from the blockchain.
+ RecoverState,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Subcommand)]
+pub enum StateReadCommand {
+ /// Display account details.
+ DisplayAccount,
+ /// Display full account history.
+ History,
+ /// Display application configuration.
+ AppConfig,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Subcommand)]
+pub enum ContractInteractionCommand {
+ /// Create new shielder account.
+ NewAccount(NewAccountCmd),
+ /// Shield some tokens.
+ Deposit(DepositCmd),
+ /// Unshield some tokens.
+ Withdraw(WithdrawCmd),
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Args)]
+pub struct NewAccountCmd {
+ /// Amount of the token to be shielded.
+ pub amount: u128,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Args)]
+pub struct DepositCmd {
+ /// Amount of the token to be shielded.
+ pub amount: u128,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Args)]
+pub struct WithdrawCmd {
+ /// Amount of the token to be shielded.
+ pub amount: u128,
+ /// Address to which the tokens should be sent.
+ pub to: Address,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, ValueEnum)]
+pub enum LoggingFormat {
+ #[default]
+ Text,
+ Json,
+}
+
+mod parsing {
+ use std::{path::PathBuf, str::FromStr};
+
+ use anyhow::{anyhow, Result};
+
+ pub fn parse_path(path: &str) -> Result {
+ let expanded_path =
+ shellexpand::full(path).map_err(|e| anyhow!("Failed to expand path: {e:?}"))?;
+ PathBuf::from_str(expanded_path.as_ref())
+ .map_err(|e| anyhow!("Failed to interpret path: {e:?}"))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn verify_cli() {
+ use clap::CommandFactory;
+ crate::config::CliConfig::command().debug_assert()
+ }
+}
diff --git a/crates/shielder-cli/src/main.rs b/crates/shielder-cli/src/main.rs
new file mode 100644
index 00000000..b82a5a6d
--- /dev/null
+++ b/crates/shielder-cli/src/main.rs
@@ -0,0 +1,139 @@
+use std::{env, io};
+
+use anyhow::{anyhow, Result};
+use clap::Parser;
+use tracing::info;
+use tracing_subscriber::EnvFilter;
+
+use crate::{
+ app_state::{AppState, RelayerRpcUrl},
+ config::{
+ CliConfig,
+ Command::{ContractInteraction, StateRead, StateWrite},
+ ContractInteractionCommand, DepositCmd, LoggingFormat, NewAccountCmd, StateReadCommand,
+ StateWriteCommand, WithdrawCmd,
+ },
+ recovery::recover_state,
+ shielder_ops::{deposit, new_account, withdraw},
+ state_file::{create_and_save_new_state, get_app_state, save_app_state},
+};
+
+mod app_state;
+mod config;
+mod recovery;
+mod shielder_ops;
+mod state_file;
+
+fn init_logging(format: LoggingFormat) -> Result<()> {
+ const LOG_CONFIGURATION_ENVVAR: &str = "RUST_LOG";
+
+ let filter = EnvFilter::new(
+ env::var(LOG_CONFIGURATION_ENVVAR)
+ .as_deref()
+ .unwrap_or("debug"),
+ );
+
+ let subscriber = tracing_subscriber::fmt()
+ .with_writer(io::stdout)
+ .with_target(true)
+ .with_env_filter(filter);
+
+ match format {
+ LoggingFormat::Json => subscriber.json().try_init(),
+ LoggingFormat::Text => subscriber.try_init(),
+ }
+ .map_err(|err| anyhow!(err))
+}
+
+async fn perform_state_write_action(
+ app_state: &mut AppState,
+ command: StateWriteCommand,
+) -> Result<()> {
+ match command {
+ StateWriteCommand::Initialize { .. } => {
+ unreachable!("State initialization should have been handled in a different context")
+ }
+ StateWriteCommand::NodeUrl { node } => {
+ info!("Setting node address to {node}");
+ app_state.node_rpc_url = node;
+ }
+ StateWriteCommand::ContractAddress { address } => {
+ info!("Setting contract address to {address}");
+ app_state.contract_address = address;
+ }
+ StateWriteCommand::RelayerUrl { url } => {
+ let relayer_rpc_url = RelayerRpcUrl::new(url.clone());
+ relayer_rpc_url.check_connection().await?;
+ info!("Setting relayer url to {url}");
+ app_state.relayer_rpc_url = relayer_rpc_url;
+ }
+ StateWriteCommand::RelayerAddress { address } => {
+ info!("Setting relayer address to {address}");
+ app_state.relayer_address = address;
+ }
+ StateWriteCommand::RecoverState => {
+ recover_state(app_state).await?;
+ }
+ };
+ Ok(())
+}
+
+fn perform_state_read_action(app_state: &AppState, command: StateReadCommand) -> Result<()> {
+ match command {
+ StateReadCommand::DisplayAccount => {
+ println!("{}", app_state.account)
+ }
+ StateReadCommand::History => {
+ println!("{:#?}", app_state.account.history)
+ }
+ StateReadCommand::AppConfig => {
+ println!("{}", app_state.display_app_config())
+ }
+ };
+ Ok(())
+}
+
+async fn perform_contract_action(
+ app_state: &mut AppState,
+ command: ContractInteractionCommand,
+) -> Result<()> {
+ match command {
+ ContractInteractionCommand::Deposit(DepositCmd { amount }) => {
+ deposit(app_state, amount).await
+ }
+ ContractInteractionCommand::Withdraw(WithdrawCmd { amount, to }) => {
+ withdraw(app_state, amount, to).await
+ }
+ ContractInteractionCommand::NewAccount(NewAccountCmd { amount }) => {
+ new_account(app_state, amount).await
+ }
+ }
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let cli_config = CliConfig::parse();
+ init_logging(cli_config.logging_format)?;
+
+ let password = cli_config.password()?;
+
+ if let StateWrite(StateWriteCommand::Initialize { private_key }) = cli_config.command {
+ create_and_save_new_state(&cli_config.state_file, &password, &private_key)?;
+ } else {
+ let mut app_state = get_app_state(&cli_config.state_file, &password)?;
+
+ match cli_config.command {
+ StateWrite(cmd) => {
+ perform_state_write_action(&mut app_state, cmd).await?;
+ save_app_state(&app_state, &cli_config.state_file, &password)?;
+ }
+ StateRead(cmd) => perform_state_read_action(&app_state, cmd)?,
+ ContractInteraction(cmd) => {
+ perform_contract_action(&mut app_state, cmd).await?;
+ save_app_state(&app_state, &cli_config.state_file, &password)?;
+ }
+ }
+ }
+
+ Ok(())
+}
diff --git a/crates/shielder-cli/src/recovery.rs b/crates/shielder-cli/src/recovery.rs
new file mode 100644
index 00000000..bc01409f
--- /dev/null
+++ b/crates/shielder-cli/src/recovery.rs
@@ -0,0 +1,129 @@
+use alloy_eips::BlockNumberOrTag;
+use alloy_primitives::{BlockHash, BlockNumber, U256};
+use alloy_provider::Provider;
+use alloy_rpc_types_eth::Transaction;
+use alloy_sol_types::SolCall;
+use anyhow::{anyhow, bail, Result};
+use shielder_circuits::{utils::padded_hash, F};
+use shielder_rust_sdk::{
+ account::{ShielderAccount, ShielderAction},
+ contract::{
+ call_type::DryRun,
+ events::get_event,
+ providers::create_simple_provider,
+ ShielderContract::{
+ depositNativeCall, newAccountNativeCall, withdrawNativeCall, DepositNative,
+ NewAccountNative, ShielderContractEvents, WithdrawNative,
+ },
+ },
+ conversion::{field_to_u256, u256_to_field},
+};
+use tracing::{error, info};
+
+use crate::app_state::AppState;
+
+pub async fn recover_state(app_state: &mut AppState) -> Result<()> {
+ let shielder_user = app_state.create_shielder_user();
+ let AppState {
+ account,
+ node_rpc_url,
+ ..
+ } = app_state;
+
+ let mut recovering_account = account.clone();
+
+ let provider = create_simple_provider(node_rpc_url).await?;
+
+ loop {
+ info!("Recovering state for nonce {}", recovering_account.nonce);
+
+ // Calculate the expected nullifier hash
+ let expected_nullifier = recovering_account.previous_nullifier();
+ let expected_nullifier_hash =
+ field_to_u256(padded_hash::(&[u256_to_field(expected_nullifier)]));
+
+ // Check if the nullifier hash has already been registered in the contract.
+ let mut block_number = shielder_user
+ .nullifiers::(expected_nullifier_hash)
+ .await?;
+ if block_number == U256::ZERO {
+ info!("Nullifier hash {expected_nullifier_hash} not found, recovering state completed");
+ break;
+ };
+ block_number -= U256::from(1); // remove the offset for null detection
+ if block_number >= U256::from(BlockNumber::MAX) {
+ let msg = format!("Block number too large: {block_number}");
+ error!(msg);
+ bail!(msg);
+ }
+ let block_number = block_number.into_limbs()[0];
+ info!("Nullifier hash {expected_nullifier_hash} found in block {block_number}");
+
+ // If yes, find the corresponding transaction.
+ let action =
+ find_shielder_transaction(&provider, block_number, &recovering_account).await?;
+
+ // Apply the action to the account.
+ recovering_account.register_action(action);
+ }
+
+ *account = recovering_account;
+
+ Ok(())
+}
+
+async fn find_shielder_transaction(
+ provider: &impl Provider,
+ block_number: BlockNumber,
+ account: &ShielderAccount,
+) -> Result {
+ let block = provider
+ .get_block_by_number(BlockNumberOrTag::Number(block_number), true)
+ .await?
+ .ok_or(anyhow!("Block not found"))?;
+ let txs = block
+ .transactions
+ .as_transactions()
+ .expect("We should get full transactions");
+
+ for tx in txs {
+ let Some(event) = try_get_shielder_event_for_tx(provider, tx, block.header.hash).await?
+ else {
+ continue;
+ };
+ let event_note = event.note();
+ let action = ShielderAction::from((tx.hash, event));
+
+ let mut hypothetical_account = account.clone();
+ hypothetical_account.register_action(action.clone());
+ let expected_note = hypothetical_account
+ .note()
+ .expect("We have just made an action");
+
+ if expected_note == event_note {
+ return Ok(action);
+ }
+ }
+ bail!("No matching Shielder transaction found in block {block_number}")
+}
+
+async fn try_get_shielder_event_for_tx(
+ provider: &impl Provider,
+ tx: &Transaction,
+ block_hash: BlockHash,
+) -> Result