diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000000..dc69733e1b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,83 @@
+# Google C/C++ Code Style settings
+# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+# Author: Kehan Xue, kehan.xue (at) gmail.com
+
+Language: Cpp
+BasedOnStyle: Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: None
+AlignOperands: Align
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: Empty
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding
+AllowShortLambdasOnASingleLine: Inline
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: None
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: true
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterStruct: false
+ AfterControlStatement: Never
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ IndentBraces: false
+ SplitEmptyFunction: false
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: false
+BreakBeforeBinaryOperators: None
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList: BeforeColon
+ColumnLimit: 80
+CompactNamespaces: false
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false # Make sure the * or & align on the left
+EmptyLineBeforeAccessModifier: LogicalBlock
+FixNamespaceComments: true
+IncludeBlocks: Preserve
+IndentCaseLabels: true
+IndentPPDirectives: None
+IndentWidth: 2
+KeepEmptyLinesAtTheStartOfBlocks: true
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PointerAlignment: Left
+ReflowComments: false
+# SeparateDefinitionBlocks: Always # Only support since clang-format 14
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: c++11
+TabWidth: 4
+UseTab: Never
\ No newline at end of file
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index d12a1d16aa..a6fbda6190 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -1,3 +1,5 @@
+# Note: this is only compatible with Linux runners.
+
name: Test setup
inputs:
pull_token:
@@ -99,6 +101,16 @@ runs:
else
echo "pkg-config and libssl-dev are already installed."
fi
-
+
+ - name: Echo docker buildx version
+ shell: bash
+ run: docker buildx version
+
- name: Set up Docker
+ uses: crazy-max/ghaction-setup-docker@v3
+
+ - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
+ with:
+ driver-opts: |
+ image=public.ecr.aws/vend/moby/buildkit:buildx-stable-1
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 251c44d529..a96b132e2a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -22,7 +22,7 @@ jobs:
cpu=64,
ram=256,
family=m7i+m7a,
- hdd=80,
+ disk=large,
image=ubuntu22-full-x64,
spot=false,
"run-id=${{ github.run_id }}",
@@ -54,7 +54,7 @@ jobs:
cpu=64,
ram=256,
family=m7i+m7a,
- hdd=80,
+ disk=large,
image=ubuntu22-full-x64,
spot=false,
"run-id=${{ github.run_id }}",
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 81958dba2c..7f494bae74 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -25,6 +25,7 @@ jobs:
runs-on,
runner=64cpu-linux-x64,
spot=false,
+ disk=large,
"run-id=${{ github.run_id }}",
]
env:
@@ -36,6 +37,13 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run cargo check
uses: actions-rs/cargo@v1
with:
@@ -61,6 +69,7 @@ jobs:
runs-on,
runner=64cpu-linux-arm64,
spot=false,
+ disk=large,
"run-id=${{ github.run_id }}",
]
env:
@@ -72,6 +81,13 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run cargo check
uses: actions-rs/cargo@v1
with:
@@ -92,7 +108,7 @@ jobs:
lint:
name: Formatting & Clippy
- runs-on: [runs-on, runner=8cpu-linux-x64, "run-id=${{ github.run_id }}"]
+ runs-on: [runs-on, runner=16cpu-linux-x64, "run-id=${{ github.run_id }}"]
env:
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
steps:
@@ -102,6 +118,13 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
@@ -110,6 +133,14 @@ jobs:
env:
CARGO_INCREMENTAL: 1
+ - name: Check test-artifacts
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: -p test-artifacts
+ env:
+ CARGO_INCREMENTAL: 1
+
- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
@@ -118,12 +149,50 @@ jobs:
env:
CARGO_INCREMENTAL: 1
+ check:
+ name: Cargo Check
+ runs-on: [runs-on, runner=16cpu-linux-x64, disk=medium, "run-id=${{ github.run_id }}"]
+ env:
+ CARGO_NET_GIT_FETCH_WITH_CLI: "true"
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@v4
+
+ - name: Setup CI
+ uses: ./.github/actions/setup
+
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
+ - name: Check workspace no features
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --workspace --all-targets --no-default-features
+
+ - name: Check workspace with default features
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --workspace --all-targets
+
+ - name: Check workspace with all features
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --workspace --all-targets --all-features
+
examples:
name: Examples
runs-on:
[
runs-on,
runner=64cpu-linux-x64,
+ disk=large,
spot=false,
"run-id=${{ github.run_id }}",
]
@@ -136,9 +205,12 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
- - name: Install SP1 toolchain
+ - name: Install SP1 toolchain from repo
run: |
cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
- name: Run cargo fmt
run: |
@@ -155,39 +227,9 @@ jobs:
cd ./examples/
cargo clippy --all-targets --all-features -- -D warnings -A incomplete-features
- tests:
- name: Tests
- runs-on: [runs-on, runner=64cpu-linux-x64, "run-id=${{ github.run_id }}"]
- steps:
- - name: Checkout sources
- uses: actions/checkout@v4
-
- - name: Setup CI
- uses: ./.github/actions/setup
-
- - name: Install SP1 toolchain
- run: |
- cargo install --locked --force --path crates/cli
- cargo prove install-toolchain
-
- - name: Run cargo fmt
- run: |
- cd ./tests/
- cargo fmt --all -- --check
-
- - name: Run cargo clippy
- run: |
- cd ./tests/
- cargo clippy --all-targets --all-features -- -D warnings -A incomplete-features
-
- - name: Build test ELF files
- run: |
- cd ./tests/
- make
-
cli:
name: CLI
- runs-on: [runs-on, runner=8cpu-linux-x64, "run-id=${{ github.run_id }}"]
+ runs-on: [runs-on, runner=8cpu-linux-x64, disk=large, "run-id=${{ github.run_id }}"]
env:
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
steps:
@@ -197,17 +239,12 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
- - name: Install SP1 toolchain
- run: |
- curl -L https://sp1.succinct.xyz | bash
- ~/.sp1/bin/sp1up
- ~/.sp1/bin/cargo-prove prove --version
-
- - name: Install SP1 CLI
+ - name: Install SP1 toolchain from repo
run: |
+ cargo run -p sp1-cli -- prove install-toolchain
cd crates/cli
- cargo install --force --locked --path .
- cd ~
+ cargo install --locked --force --path .
+ cargo clean
- name: Run cargo prove new
run: |
@@ -236,11 +273,12 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
- - name: Install SP1 toolchain
+ - name: Install SP1 toolchain from repo
run: |
- curl -L https://sp1.succinct.xyz | bash
- ~/.sp1/bin/sp1up
- ~/.sp1/bin/cargo-prove prove --version
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
- name: Run Evaluation
run: |
@@ -268,6 +306,7 @@ jobs:
[
runs-on,
"ram=${{ matrix.mem_limit}}",
+ disk=large,
family=c7a,
image=ubuntu22-full-x64,
"run-id=${{ github.run_id }}",
@@ -281,17 +320,12 @@ jobs:
- name: Setup CI
uses: ./.github/actions/setup
- - name: Install SP1 toolchain
- run: |
- curl -L https://sp1.succinct.xyz | bash
- ~/.sp1/bin/sp1up
- ~/.sp1/bin/cargo-prove prove --version
-
- - name: Install SP1 CLI
+ - name: Install SP1 toolchain from repo
run: |
+ cargo run -p sp1-cli -- prove install-toolchain
cd crates/cli
- cargo install --force --locked --path .
- cd ~
+ cargo install --locked --force --path .
+ cargo clean
- name: Run tendermint script
run: |
@@ -335,7 +369,7 @@ jobs:
# - name: "Install cargo-prove"
# run: |
- # cargo install --locked --path ./crates/cli
+ # cargo install --locked --force --path ./crates/cli
# - name: "Install SP1 toolchain"
# run: |
@@ -420,9 +454,12 @@ jobs:
runs-on:
[
runs-on,
- runner=64cpu-linux-x64,
+ cpu=64,
+ ram=256,
+ family=m7i+m7a,
+ disk=large,
+ image=ubuntu22-full-x64,
spot=false,
- hdd=150,
"run-id=${{ github.run_id }}",
]
env:
@@ -438,13 +475,14 @@ jobs:
run: |
find -name Cargo.lock -type f -exec rm {} \;
- - name: "Build SP1 without lock files"
- run: |
- cargo build --all --all-targets
-
+ # We need the SP1 toolchain to be installed in order to build test-artifacts
- name: Install SP1 toolchain
run: |
cargo run -p sp1-cli -- prove install-toolchain
+
+ - name: "Build SP1 without lock files"
+ run: |
+ cargo build --all --all-targets
- name: "Build examples without lock files"
run: |
diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml
index f54af577f5..3841ae8adb 100644
--- a/.github/workflows/release-plz.yml
+++ b/.github/workflows/release-plz.yml
@@ -8,6 +8,7 @@ on:
push:
branches:
- main
+ workflow_dispatch:
jobs:
release-plz:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e752edd077..65ef34ab73 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -86,12 +86,12 @@ jobs:
# `platform` and `arch`: Used in tarball names
# `svm`: target platform to use for the Solc binary: https://github.com/roynalnaruto/svm-rs/blob/84cbe0ac705becabdc13168bae28a45ad2299749/svm-builds/build.rs#L4-L24
- runner: ubuntu-latest
- target: x86_64-unknown-linux-gnu
+ target: x86_64-unknown-linux-musl
svm_target_platform: linux-amd64
platform: linux
arch: amd64
- runner: warp-ubuntu-latest-arm64-4x
- target: aarch64-unknown-linux-gnu
+ target: aarch64-unknown-linux-musl
svm_target_platform: linux-aarch64
platform: linux
arch: arm64
@@ -148,12 +148,19 @@ jobs:
echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV
- name: Linux ARM setup
- if: matrix.target == 'aarch64-unknown-linux-gnu'
+ if: matrix.target == 'aarch64-unknown-linux-musl'
run: |
sudo apt-get update -y
sudo apt-get install -y gcc-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
+ - name: Musl setup
+ if: contains(matrix.target, 'musl')
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y musl-tools musl-dev
+ rustup target add ${{ matrix.target }}
+
- name: Build binaries
env:
SVM_TARGET_PLATFORM: ${{ matrix.svm_target_platform }}
@@ -225,6 +232,77 @@ jobs:
${{ steps.artifacts.outputs.file_name }}
${{ steps.man.outputs.cargo_prove_man }}
+ toolchain-test:
+ name: "Test toolchain installation (${{ matrix.name }})"
+ needs: release
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: "Ubuntu 24.04 (x86_64)"
+ runner: "ubuntu-24.04"
+ - name: "Ubuntu 22.04 (x86_64)"
+ runner: "ubuntu-22.04"
+ - name: "Ubuntu 20.04 (x86_64)"
+ runner: "ubuntu-20.04"
+ - name: "macOS Monterey (x86_64)"
+ runner: "macos-12"
+ - name: "macOS Ventura (x86_64)"
+ runner: "macos-13"
+ - name: "macOS Sonoma (ARM64)"
+ runner: "macos-14"
+
+ runs-on: "${{ matrix.runner }}"
+ steps:
+ - name: "Checkout source code"
+ uses: "actions/checkout@v4"
+
+ - name: "Install SP1"
+ env:
+ SP1UP_VERSION: ${{ github.ref_name }}
+ run: |
+ cd sp1up
+ chmod +x sp1up
+ ./sp1up --token ${{ secrets.GITHUB_TOKEN }}
+
+ - name: "Create SP1 project from template"
+ run: |
+ $HOME/.sp1/bin/cargo-prove prove new --bare hello
+
+ - name: "Build SP1 project"
+ run: |
+ cd ./hello/program
+ $HOME/.sp1/bin/cargo-prove prove build
+
+ toolchain-test-ec2:
+ name: "Test toolchain installation (${{ matrix.name }})"
+ needs: release
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # AMI from `us-east-1`
+ - name: "Debian 12 (x86_64)"
+ ec2-instance: "c5.2xlarge"
+ ami: "ami-064519b8c76274859"
+ volume: "/dev/xvda"
+ - name: "Debian 12 (ARM64)"
+ ec2-instance: "c6g.2xlarge"
+ ami: "ami-0789039e34e739d67"
+ volume: "/dev/xvda"
+ uses: "./.github/workflows/toolchain-ec2.yml"
+ with:
+ image-id: "${{ matrix.ami }}"
+ instance-type: "${{ matrix.ec2-instance }}"
+ root-volume: "${{ matrix.volume }}"
+ secrets:
+ AWS_REGION: "${{ secrets.AWS_REGION }}"
+ AWS_ACCESS_KEY_ID: "${{ secrets.AWS_ACCESS_KEY_ID }}"
+ AWS_SECRET_ACCESS_KEY: "${{ secrets.AWS_SECRET_ACCESS_KEY }}"
+ AWS_SUBNET_ID: "${{ secrets.AWS_SUBNET_ID }}"
+ AWS_SG_ID: "${{ secrets.AWS_SG_ID }}"
+ GH_PAT: ${{ secrets.GH_PAT }}
+
cleanup:
name: Release cleanup
runs-on: ubuntu-latest
diff --git a/.github/workflows/suite.yml b/.github/workflows/suite.yml
index ca39cabe1c..f4b2826390 100644
--- a/.github/workflows/suite.yml
+++ b/.github/workflows/suite.yml
@@ -59,6 +59,13 @@ jobs:
command: clean
toolchain: 1.81.0
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run sp1-perf
uses: actions-rs/cargo@v1
with:
@@ -67,6 +74,7 @@ jobs:
args: --release -p sp1-perf -- --program workdir/program.bin --stdin workdir/stdin.bin --mode cpu
env:
RUST_LOG: info
+ VERIFY_VK: false
RUSTFLAGS: -Copt-level=3 -Ctarget-cpu=native
RUST_BACKTRACE: 1
@@ -81,7 +89,7 @@ jobs:
[
"runs-on",
"family=g6.4xlarge",
- "hdd=200",
+ "disk=large",
"ami=ami-0a63dc9cb9e934ba3",
"spot=false",
"run-id=${{ github.run_id }}",
@@ -112,6 +120,13 @@ jobs:
command: clean
toolchain: 1.81.0
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run sp1-perf
uses: actions-rs/cargo@v1
with:
@@ -120,6 +135,7 @@ jobs:
args: --release -p sp1-perf -- --program workdir/program.bin --stdin workdir/stdin.bin --mode cuda
env:
RUST_LOG: debug
+ VERIFY_VK: false
RUSTFLAGS: -Copt-level=3 -Ctarget-cpu=native
RUST_BACKTRACE: 1
SP1_PROVER: cuda
@@ -164,6 +180,13 @@ jobs:
command: clean
toolchain: 1.81.0
+ - name: Install SP1 toolchain from repo
+ run: |
+ cargo run -p sp1-cli -- prove install-toolchain
+ cd crates/cli
+ cargo install --locked --force --path .
+ cargo clean
+
- name: Run sp1-perf
uses: actions-rs/cargo@v1
with:
@@ -172,6 +195,7 @@ jobs:
args: --release -p sp1-perf --features "native-gnark,network-v2" -- --program workdir/program.bin --stdin workdir/stdin.bin --mode network
env:
RUST_LOG: info
+ VERIFY_VK: false
RUSTFLAGS: -Copt-level=3 -Ctarget-cpu=native
RUST_BACKTRACE: 1
SP1_PROVER: network
diff --git a/.github/workflows/toolchain-ec2.yml b/.github/workflows/toolchain-ec2.yml
index dd3b2457f4..bbc4f6d117 100644
--- a/.github/workflows/toolchain-ec2.yml
+++ b/.github/workflows/toolchain-ec2.yml
@@ -92,15 +92,24 @@ jobs:
- name: "Install build dependencies"
run: |
sudo apt-get update
- sudo apt-get install -y build-essential pkg-config libssl-dev
+ sudo apt-get install -y build-essential pkg-config libssl-dev git
- - name: "Install cargo-prove"
+ - name: "Install SP1"
+ env:
+ SP1UP_VERSION: ${{ github.ref_name }}
run: |
- cargo install --locked --path ./crates/cli
+ cd sp1up
+ chmod +x sp1up
+ ./sp1up --token ${{ secrets.GH_PAT }}
- - name: "Install SP1 toolchain"
+ - name: "Create SP1 project from template"
run: |
- cargo prove install-toolchain --token ${{ secrets.GH_PAT }}
+ $HOME/.sp1/bin/cargo-prove prove new --bare hello
+
+ - name: "Build SP1 project"
+ run: |
+ cd ./hello/program
+ $HOME/.sp1/bin/cargo-prove prove build
stop-runner:
name: "Stop self-hosted EC2 runner"
diff --git a/.vscode/settings.json b/.vscode/settings.json
index d1500a8b1a..f3522916a0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -66,4 +66,22 @@
// "rust-analyzer.check.workspace": false,
// "rust-analyzer.check.invocationStrategy": "once",
// "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
+ "C_Cpp.default.includePath": [
+ "${workspaceFolder}/crates/**/include",
+ "${workspaceFolder}/target/include",
+ ],
+ "C_Cpp.intelliSenseEngine": "Tag Parser",
+ "files.associations": {
+ "random": "cpp",
+ "chrono": "cpp",
+ "cstdint": "cpp",
+ "ratio": "cpp",
+ "system_error": "cpp",
+ "array": "cpp",
+ "functional": "cpp",
+ "tuple": "cpp",
+ "type_traits": "cpp",
+ "utility": "cpp",
+ "cmath": "cpp"
+ },
}
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 2a9ba70be9..7041092a11 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -105,9 +105,9 @@ dependencies = [
[[package]]
name = "allocator-api2"
-version = "0.2.18"
+version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
[[package]]
name = "alloy-consensus"
@@ -168,9 +168,9 @@ dependencies = [
[[package]]
name = "alloy-json-abi"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ded610181f3dad5810f6ff12d1a99994cf9b42d2fcb7709029352398a5da5ae6"
+checksum = "b84c506bf264110fa7e90d9924f742f40ef53c6572ea56a0b0bd714a567ed389"
dependencies = [
"alloy-primitives",
"alloy-sol-type-parser",
@@ -188,7 +188,7 @@ dependencies = [
"alloy-sol-types",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
"tracing",
]
@@ -210,7 +210,7 @@ dependencies = [
"async-trait",
"auto_impl",
"futures-utils-wasm",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -228,9 +228,9 @@ dependencies = [
[[package]]
name = "alloy-primitives"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5"
+checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425"
dependencies = [
"alloy-rlp",
"bytes 1.8.0",
@@ -317,7 +317,7 @@ dependencies = [
"auto_impl",
"elliptic-curve",
"k256",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -333,14 +333,14 @@ dependencies = [
"async-trait",
"k256",
"rand 0.8.5",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
name = "alloy-sol-macro"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a1b42ac8f45e2f49f4bcdd72cbfde0bb148f5481d403774ffa546e48b83efc1"
+checksum = "9343289b4a7461ed8bab8618504c995c049c082b70c7332efd7b32125633dc05"
dependencies = [
"alloy-sol-macro-expander",
"alloy-sol-macro-input",
@@ -352,13 +352,13 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-expander"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06318f1778e57f36333e850aa71bd1bb5e560c10279e236622faae0470c50412"
+checksum = "4222d70bec485ceccc5d8fd4f2909edd65b5d5e43d4aca0b5dcee65d519ae98f"
dependencies = [
"alloy-sol-macro-input",
"const-hex",
- "heck",
+ "heck 0.5.0",
"indexmap 2.6.0",
"proc-macro-error2",
"proc-macro2",
@@ -370,13 +370,13 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-input"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaebb9b0ad61a41345a22c9279975c0cdd231b97947b10d7aad1cf0a7181e4a5"
+checksum = "2e17f2677369571b976e51ea1430eb41c3690d344fef567b840bfc0b01b6f83a"
dependencies = [
"const-hex",
"dunce",
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.87",
@@ -385,9 +385,9 @@ dependencies = [
[[package]]
name = "alloy-sol-type-parser"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12c71028bfbfec210e24106a542aad3def7caf1a70e2c05710e92a98481980d3"
+checksum = "aa64d80ae58ffaafdff9d5d84f58d03775f66c84433916dc9a64ed16af5755da"
dependencies = [
"serde",
"winnow 0.6.20",
@@ -395,9 +395,9 @@ dependencies = [
[[package]]
name = "alloy-sol-types"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "374d7fb042d68ddfe79ccb23359de3007f6d4d53c13f703b64fb0db422132111"
+checksum = "6520d427d4a8eb7aa803d852d7a52ceb0c519e784c292f64bb339e636918cf27"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
@@ -487,13 +487,61 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.92"
+version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13"
+checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
dependencies = [
"backtrace",
]
+[[package]]
+name = "ark-bn254"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f"
+dependencies = [
+ "ark-ec",
+ "ark-ff 0.4.2",
+ "ark-std 0.4.0",
+]
+
+[[package]]
+name = "ark-crypto-primitives"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56"
+dependencies = [
+ "ark-ec",
+ "ark-ff 0.4.2",
+ "ark-relations",
+ "ark-serialize 0.4.2",
+ "ark-snark",
+ "ark-std 0.4.0",
+ "blake2",
+ "derivative",
+ "digest 0.10.7",
+ "rayon",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "ark-ec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba"
+dependencies = [
+ "ark-ff 0.4.2",
+ "ark-poly",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+ "derivative",
+ "hashbrown 0.13.2",
+ "itertools 0.10.5",
+ "num-traits",
+ "rayon",
+ "zeroize",
+]
+
[[package]]
name = "ark-ff"
version = "0.3.0"
@@ -528,6 +576,7 @@ dependencies = [
"num-bigint 0.4.6",
"num-traits",
"paste",
+ "rayon",
"rustc_version 0.4.1",
"zeroize",
]
@@ -577,6 +626,48 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "ark-groth16"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc"
+dependencies = [
+ "ark-crypto-primitives",
+ "ark-ec",
+ "ark-ff 0.4.2",
+ "ark-poly",
+ "ark-relations",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+ "rayon",
+]
+
+[[package]]
+name = "ark-poly"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf"
+dependencies = [
+ "ark-ff 0.4.2",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+ "derivative",
+ "hashbrown 0.13.2",
+ "rayon",
+]
+
+[[package]]
+name = "ark-relations"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0"
+dependencies = [
+ "ark-ff 0.4.2",
+ "ark-std 0.4.0",
+ "tracing",
+ "tracing-subscriber 0.2.25",
+]
+
[[package]]
name = "ark-serialize"
version = "0.3.0"
@@ -593,11 +684,35 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
dependencies = [
+ "ark-serialize-derive",
"ark-std 0.4.0",
"digest 0.10.7",
"num-bigint 0.4.6",
]
+[[package]]
+name = "ark-serialize-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-snark"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63"
+dependencies = [
+ "ark-ff 0.4.2",
+ "ark-relations",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+]
+
[[package]]
name = "ark-std"
version = "0.3.0"
@@ -616,6 +731,7 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
dependencies = [
"num-traits",
"rand 0.8.5",
+ "rayon",
]
[[package]]
@@ -671,8 +787,8 @@ checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
"async-task",
"concurrent-queue",
- "fastrand 2.1.1",
- "futures-lite 2.4.0",
+ "fastrand 2.2.0",
+ "futures-lite 2.5.0",
"slab",
]
@@ -687,21 +803,21 @@ dependencies = [
"async-io",
"async-lock",
"blocking",
- "futures-lite 2.4.0",
+ "futures-lite 2.5.0",
"once_cell",
]
[[package]]
name = "async-io"
-version = "2.3.4"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
+checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
dependencies = [
"async-lock",
"cfg-if",
"concurrent-queue",
"futures-io",
- "futures-lite 2.4.0",
+ "futures-lite 2.5.0",
"parking",
"polling",
"rustix",
@@ -736,7 +852,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-io",
- "futures-lite 2.4.0",
+ "futures-lite 2.5.0",
"gloo-timers",
"kv-log-macro",
"log",
@@ -1066,7 +1182,7 @@ dependencies = [
"async-channel 2.3.1",
"async-task",
"futures-io",
- "futures-lite 2.4.0",
+ "futures-lite 2.5.0",
"piper",
]
@@ -1192,7 +1308,7 @@ dependencies = [
"semver 1.0.23",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1201,11 +1317,30 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+[[package]]
+name = "cbindgen"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
+dependencies = [
+ "clap",
+ "heck 0.4.1",
+ "indexmap 2.6.0",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 2.0.87",
+ "tempfile",
+ "toml",
+]
+
[[package]]
name = "cc"
-version = "1.1.36"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
dependencies = [
"jobserver",
"libc",
@@ -1320,7 +1455,7 @@ version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.87",
@@ -1356,7 +1491,7 @@ dependencies = [
"encode_unicode 0.3.6",
"lazy_static",
"libc",
- "unicode-width",
+ "unicode-width 0.1.14",
"windows-sys 0.52.0",
]
@@ -1426,9 +1561,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
dependencies = [
"libc",
]
@@ -1475,6 +1610,15 @@ dependencies = [
"itertools 0.10.5",
]
+[[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"
@@ -1540,9 +1684,9 @@ dependencies = [
[[package]]
name = "csv"
-version = "1.3.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
+checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
@@ -1595,9 +1739,9 @@ dependencies = [
[[package]]
name = "curl-sys"
-version = "0.4.77+curl-8.10.1"
+version = "0.4.78+curl-8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f469e8a5991f277a208224f6c7ad72ecb5f986e36d09ae1f2c1bb9259478a480"
+checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf"
dependencies = [
"cc",
"libc",
@@ -2044,9 +2188,9 @@ dependencies = [
[[package]]
name = "fastrand"
-version = "2.1.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]]
name = "fastrlp"
@@ -2241,11 +2385,11 @@ dependencies = [
[[package]]
name = "futures-lite"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210"
+checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
dependencies = [
- "fastrand 2.1.1",
+ "fastrand 2.2.0",
"futures-core",
"futures-io",
"parking",
@@ -2497,6 +2641,15 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
[[package]]
name = "hashbrown"
version = "0.14.5"
@@ -2520,6 +2673,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
[[package]]
name = "heck"
version = "0.5.0"
@@ -2979,15 +3138,15 @@ dependencies = [
[[package]]
name = "indicatif"
-version = "0.17.8"
+version = "0.17.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
+checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281"
dependencies = [
"console",
- "instant",
"number_prefix",
"portable-atomic",
- "unicode-width",
+ "unicode-width 0.2.0",
+ "web-time",
]
[[package]]
@@ -3169,9 +3328,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.161"
+version = "0.2.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
[[package]]
name = "libgit2-sys"
@@ -3665,7 +3824,7 @@ dependencies = [
[[package]]
name = "p3-air"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"p3-field",
"p3-matrix",
@@ -3674,7 +3833,7 @@ dependencies = [
[[package]]
name = "p3-baby-bear"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"num-bigint 0.4.6",
"p3-field",
@@ -3688,7 +3847,7 @@ dependencies = [
[[package]]
name = "p3-bn254-fr"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"ff 0.13.0",
"num-bigint 0.4.6",
@@ -3702,7 +3861,7 @@ dependencies = [
[[package]]
name = "p3-challenger"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"p3-field",
"p3-maybe-rayon",
@@ -3715,7 +3874,7 @@ dependencies = [
[[package]]
name = "p3-commit"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-challenger",
@@ -3728,7 +3887,7 @@ dependencies = [
[[package]]
name = "p3-dft"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"p3-field",
"p3-matrix",
@@ -3740,7 +3899,7 @@ dependencies = [
[[package]]
name = "p3-field"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"num-bigint 0.4.6",
@@ -3753,7 +3912,7 @@ dependencies = [
[[package]]
name = "p3-fri"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-challenger",
@@ -3771,7 +3930,7 @@ dependencies = [
[[package]]
name = "p3-interpolation"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"p3-field",
"p3-matrix",
@@ -3781,7 +3940,7 @@ dependencies = [
[[package]]
name = "p3-keccak-air"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"p3-air",
"p3-field",
@@ -3794,7 +3953,7 @@ dependencies = [
[[package]]
name = "p3-matrix"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-field",
@@ -3808,7 +3967,7 @@ dependencies = [
[[package]]
name = "p3-maybe-rayon"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"rayon",
]
@@ -3816,7 +3975,7 @@ dependencies = [
[[package]]
name = "p3-mds"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-dft",
@@ -3830,7 +3989,7 @@ dependencies = [
[[package]]
name = "p3-merkle-tree"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-commit",
@@ -3846,7 +4005,7 @@ dependencies = [
[[package]]
name = "p3-poseidon2"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"gcd",
"p3-field",
@@ -3859,7 +4018,7 @@ dependencies = [
[[package]]
name = "p3-symmetric"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-field",
@@ -3869,7 +4028,7 @@ dependencies = [
[[package]]
name = "p3-uni-stark"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"itertools 0.12.1",
"p3-air",
@@ -3887,7 +4046,7 @@ dependencies = [
[[package]]
name = "p3-util"
version = "0.1.0"
-source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db"
+source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#d33eaa69b1ef96ad678ebd96ae8e75aef3508b2a"
dependencies = [
"serde",
]
@@ -3992,6 +4151,12 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+[[package]]
+name = "pathdiff"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
+
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@@ -4014,7 +4179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
dependencies = [
"memchr",
- "thiserror",
+ "thiserror 1.0.69",
"ucd-trie",
]
@@ -4067,7 +4232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
- "fastrand 2.1.1",
+ "fastrand 2.2.0",
"futures-io",
]
@@ -4123,9 +4288,9 @@ dependencies = [
[[package]]
name = "polling"
-version = "3.7.3"
+version = "3.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
+checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if",
"concurrent-queue",
@@ -4189,7 +4354,7 @@ dependencies = [
"is-terminal",
"lazy_static",
"term",
- "unicode-width",
+ "unicode-width 0.1.14",
]
[[package]]
@@ -4305,7 +4470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15"
dependencies = [
"bytes 1.8.0",
- "heck",
+ "heck 0.5.0",
"itertools 0.13.0",
"log",
"multimap",
@@ -4360,7 +4525,7 @@ dependencies = [
"rustc-hash 2.0.0",
"rustls 0.23.16",
"socket2",
- "thiserror",
+ "thiserror 1.0.69",
"tokio",
"tracing",
]
@@ -4377,7 +4542,7 @@ dependencies = [
"rustc-hash 2.0.0",
"rustls 0.23.16",
"slab",
- "thiserror",
+ "thiserror 1.0.69",
"tinyvec",
"tracing",
]
@@ -4538,7 +4703,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.15",
"libredox",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -4549,7 +4714,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
- "regex-automata 0.4.8",
+ "regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
@@ -4564,9 +4729,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -4646,7 +4811,7 @@ dependencies = [
"http 1.1.0",
"reqwest",
"serde",
- "thiserror",
+ "thiserror 1.0.69",
"tower-service",
]
@@ -4806,9 +4971,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.39"
+version = "0.38.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee"
+checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
dependencies = [
"bitflags",
"errno",
@@ -5030,9 +5195,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.12.0"
+version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
+checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
dependencies = [
"core-foundation-sys",
"libc",
@@ -5082,18 +5247,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.214"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.214"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
@@ -5130,7 +5295,16 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
dependencies = [
"percent-encoding",
"serde",
- "thiserror",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
]
[[package]]
@@ -5169,9 +5343,9 @@ dependencies = [
[[package]]
name = "serial_test"
-version = "3.1.1"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d"
+checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
dependencies = [
"futures",
"log",
@@ -5183,9 +5357,9 @@ dependencies = [
[[package]]
name = "serial_test_derive"
-version = "3.1.1"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67"
+checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
dependencies = [
"proc-macro2",
"quote",
@@ -5376,7 +5550,7 @@ dependencies = [
[[package]]
name = "sp1-build"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"anyhow",
"cargo_metadata",
@@ -5387,10 +5561,11 @@ dependencies = [
[[package]]
name = "sp1-cli"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"anstyle",
"anyhow",
+ "cargo_metadata",
"clap",
"ctrlc",
"dirs",
@@ -5415,7 +5590,7 @@ dependencies = [
[[package]]
name = "sp1-core-executor"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"bytemuck",
@@ -5439,7 +5614,8 @@ dependencies = [
"sp1-zkvm",
"strum",
"strum_macros",
- "thiserror",
+ "test-artifacts",
+ "thiserror 1.0.69",
"tiny-keccak",
"tracing",
"typenum",
@@ -5448,13 +5624,16 @@ dependencies = [
[[package]]
name = "sp1-core-machine"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
+ "cbindgen",
+ "cc",
"cfg-if",
"criterion",
"elliptic-curve",
"generic-array 1.1.0",
+ "glob",
"hashbrown 0.14.5",
"hex",
"itertools 0.13.0",
@@ -5472,7 +5651,10 @@ dependencies = [
"p3-maybe-rayon",
"p3-uni-stark",
"p3-util",
+ "pathdiff",
"rand 0.8.5",
+ "rayon",
+ "rayon-scan",
"serde",
"size",
"snowbridge-amcl",
@@ -5486,18 +5668,19 @@ dependencies = [
"strum",
"strum_macros",
"tempfile",
- "thiserror",
+ "test-artifacts",
+ "thiserror 1.0.69",
"tiny-keccak",
"tracing",
"tracing-forest",
- "tracing-subscriber",
+ "tracing-subscriber 0.3.18",
"typenum",
"web-time",
]
[[package]]
name = "sp1-cuda"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"ctrlc",
@@ -5506,6 +5689,7 @@ dependencies = [
"serde",
"sp1-core-machine",
"sp1-prover",
+ "test-artifacts",
"tokio",
"tracing",
"twirp-build-rs",
@@ -5514,7 +5698,7 @@ dependencies = [
[[package]]
name = "sp1-curves"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"cfg-if",
"curve25519-dalek",
@@ -5537,7 +5721,7 @@ dependencies = [
[[package]]
name = "sp1-derive"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"quote",
"syn 1.0.109",
@@ -5545,7 +5729,7 @@ dependencies = [
[[package]]
name = "sp1-eval"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"anyhow",
"bincode",
@@ -5563,14 +5747,16 @@ dependencies = [
[[package]]
name = "sp1-helper"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"sp1-build",
]
[[package]]
name = "sp1-lib"
-version = "3.0.0"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c8744af050832df5ca44fcd63979a83b93ca3010b2d5a5ce2a2b91f7438065c"
dependencies = [
"bincode",
"serde",
@@ -5578,9 +5764,7 @@ dependencies = [
[[package]]
name = "sp1-lib"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14deb700469a37ec075bcf88dac3815b026dd9c4b9cb175980826f1fbb2e4e80"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"serde",
@@ -5588,7 +5772,7 @@ dependencies = [
[[package]]
name = "sp1-perf"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"clap",
@@ -5598,12 +5782,13 @@ dependencies = [
"sp1-prover",
"sp1-sdk",
"sp1-stark",
+ "test-artifacts",
"time 0.3.36",
]
[[package]]
name = "sp1-primitives"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"hex",
@@ -5619,7 +5804,7 @@ dependencies = [
[[package]]
name = "sp1-prover"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"anyhow",
"bincode",
@@ -5647,14 +5832,16 @@ dependencies = [
"sp1-recursion-core",
"sp1-recursion-gnark-ffi",
"sp1-stark",
- "thiserror",
+ "test-artifacts",
+ "thiserror 1.0.69",
"tracing",
- "tracing-subscriber",
+ "tracing-appender",
+ "tracing-subscriber 0.3.18",
]
[[package]]
name = "sp1-recursion-circuit"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"ff 0.13.0",
"hashbrown 0.14.5",
@@ -5684,13 +5871,14 @@ dependencies = [
"sp1-recursion-core",
"sp1-recursion-gnark-ffi",
"sp1-stark",
+ "test-artifacts",
"tracing",
"zkhash",
]
[[package]]
name = "sp1-recursion-compiler"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"backtrace",
"criterion",
@@ -5715,12 +5903,16 @@ dependencies = [
[[package]]
name = "sp1-recursion-core"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"backtrace",
+ "cbindgen",
+ "cc",
"ff 0.13.0",
+ "glob",
"hashbrown 0.14.5",
"itertools 0.13.0",
+ "num_cpus",
"p3-air",
"p3-baby-bear",
"p3-bn254-fr",
@@ -5735,6 +5927,7 @@ dependencies = [
"p3-poseidon2",
"p3-symmetric",
"p3-util",
+ "pathdiff",
"rand 0.8.5",
"serde",
"sp1-core-machine",
@@ -5742,7 +5935,7 @@ dependencies = [
"sp1-primitives",
"sp1-stark",
"static_assertions",
- "thiserror",
+ "thiserror 1.0.69",
"tracing",
"vec_map",
"zkhash",
@@ -5750,7 +5943,7 @@ dependencies = [
[[package]]
name = "sp1-recursion-derive"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"quote",
"syn 1.0.109",
@@ -5758,7 +5951,7 @@ dependencies = [
[[package]]
name = "sp1-recursion-gnark-cli"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"bincode",
"clap",
@@ -5767,7 +5960,7 @@ dependencies = [
[[package]]
name = "sp1-recursion-gnark-ffi"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"anyhow",
"bincode",
@@ -5791,7 +5984,7 @@ dependencies = [
[[package]]
name = "sp1-sdk"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"alloy-primitives",
"alloy-signer",
@@ -5816,6 +6009,7 @@ dependencies = [
"reqwest",
"reqwest-middleware",
"serde",
+ "sp1-build",
"sp1-core-executor",
"sp1-core-machine",
"sp1-cuda",
@@ -5825,7 +6019,8 @@ dependencies = [
"strum",
"strum_macros",
"tempfile",
- "thiserror",
+ "test-artifacts",
+ "thiserror 1.0.69",
"tokio",
"tonic",
"tracing",
@@ -5835,11 +6030,12 @@ dependencies = [
[[package]]
name = "sp1-stark"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
"arrayref",
"hashbrown 0.14.5",
"itertools 0.13.0",
+ "num-bigint 0.4.6",
"num-traits",
"p3-air",
"p3-baby-bear",
@@ -5868,8 +6064,13 @@ dependencies = [
[[package]]
name = "sp1-verifier"
-version = "3.0.0"
+version = "4.0.0-rc.1"
dependencies = [
+ "ark-bn254",
+ "ark-ec",
+ "ark-ff 0.4.2",
+ "ark-groth16",
+ "ark-serialize 0.4.2",
"hex",
"lazy_static",
"num-bigint 0.4.6",
@@ -5877,12 +6078,12 @@ dependencies = [
"sha2 0.10.8",
"sp1-sdk",
"substrate-bn-succinct",
- "thiserror-no-std",
+ "thiserror 2.0.3",
]
[[package]]
name = "sp1-zkvm"
-version = "3.0.1"
+version = "4.0.0-rc.1"
dependencies = [
"cfg-if",
"getrandom 0.2.15",
@@ -5892,7 +6093,7 @@ dependencies = [
"p3-field",
"rand 0.8.5",
"sha2 0.10.8",
- "sp1-lib 3.0.0",
+ "sp1-lib 4.0.0-rc.1",
"sp1-primitives",
]
@@ -6024,7 +6225,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
@@ -6045,7 +6246,7 @@ dependencies = [
"num-bigint 0.4.6",
"rand 0.8.5",
"rustc-hex",
- "sp1-lib 3.1.0",
+ "sp1-lib 3.2.1",
]
[[package]]
@@ -6101,9 +6302,9 @@ dependencies = [
[[package]]
name = "syn-solidity"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edf42e81491fb8871b74df3d222c64ae8cbc1269ea509fa768a3ed3e1b0ac8cb"
+checksum = "f76fe0a3e1476bdaa0775b9aec5b869ed9520c2b2fedfe9c6df3618f8ea6290b"
dependencies = [
"paste",
"proc-macro2",
@@ -6187,12 +6388,12 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tempfile"
-version = "3.13.0"
+version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
- "fastrand 2.1.1",
+ "fastrand 2.2.0",
"once_cell",
"rustix",
"windows-sys 0.59.0",
@@ -6209,6 +6410,13 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "test-artifacts"
+version = "4.0.0-rc.1"
+dependencies = [
+ "sp1-build",
+]
+
[[package]]
name = "textwrap"
version = "0.16.1"
@@ -6217,47 +6425,47 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
dependencies = [
"smawk",
"unicode-linebreak",
- "unicode-width",
+ "unicode-width 0.1.14",
]
[[package]]
name = "thiserror"
-version = "1.0.68"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
]
[[package]]
-name = "thiserror-impl"
-version = "1.0.68"
+name = "thiserror"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e"
+checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.87",
+ "thiserror-impl 2.0.3",
]
[[package]]
-name = "thiserror-impl-no-std"
-version = "2.0.2"
+name = "thiserror-impl"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.87",
]
[[package]]
-name = "thiserror-no-std"
-version = "2.0.2"
+name = "thiserror-impl"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea"
+checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
- "thiserror-impl-no-std",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
]
[[package]]
@@ -6396,9 +6604,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.41.0"
+version = "1.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
+checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
dependencies = [
"backtrace",
"bytes 1.8.0",
@@ -6468,11 +6676,26 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.22.22",
+]
+
[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
[[package]]
name = "toml_edit"
@@ -6492,6 +6715,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap 2.6.0",
+ "serde",
+ "serde_spanned",
"toml_datetime",
"winnow 0.6.20",
]
@@ -6589,6 +6814,18 @@ dependencies = [
"tracing-core",
]
+[[package]]
+name = "tracing-appender"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
+dependencies = [
+ "crossbeam-channel",
+ "thiserror 1.0.69",
+ "time 0.3.36",
+ "tracing-subscriber 0.3.18",
+]
+
[[package]]
name = "tracing-attributes"
version = "0.1.27"
@@ -6618,9 +6855,9 @@ checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f"
dependencies = [
"ansi_term",
"smallvec",
- "thiserror",
+ "thiserror 1.0.69",
"tracing",
- "tracing-subscriber",
+ "tracing-subscriber 0.3.18",
]
[[package]]
@@ -6644,6 +6881,15 @@ dependencies = [
"tracing-core",
]
+[[package]]
+name = "tracing-subscriber"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
+dependencies = [
+ "tracing-core",
+]
+
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
@@ -6682,7 +6928,7 @@ dependencies = [
"log",
"rand 0.8.5",
"sha1 0.10.6",
- "thiserror",
+ "thiserror 1.0.69",
"url",
"utf-8",
]
@@ -6712,7 +6958,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
"tokio",
"tower 0.5.1",
"url",
@@ -6772,6 +7018,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+[[package]]
+name = "unicode-width"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
+
[[package]]
name = "unicode-xid"
version = "0.2.6"
diff --git a/Cargo.toml b/Cargo.toml
index 7f40570ec4..59bc200d24 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace.package]
-version = "3.0.0"
+version = "4.0.0-rc.1"
edition = "2021"
license = "MIT OR Apache-2.0"
rust-version = "1.79"
@@ -31,6 +31,7 @@ members = [
"crates/verifier",
"crates/stark",
"crates/zkvm/*",
+ "crates/test-artifacts",
]
exclude = ["examples/target"]
resolver = "2"
@@ -48,29 +49,32 @@ debug-assertions = true
[workspace.dependencies]
# sp1
-sp1-build = { path = "crates/build", version = "3.0.0" }
-sp1-cli = { path = "crates/cli", version = "3.0.0", default-features = false }
-sp1-core-machine = { path = "crates/core/machine", version = "3.0.0" }
-sp1-core-executor = { path = "crates/core/executor", version = "3.0.0" }
-sp1-curves = { path = "crates/curves", version = "3.0.0" }
-sp1-derive = { path = "crates/derive", version = "3.0.0" }
-sp1-eval = { path = "crates/eval", version = "3.0.0" }
-sp1-helper = { path = "crates/helper", version = "3.0.0", default-features = false }
-sp1-primitives = { path = "crates/primitives", version = "3.0.0" }
-sp1-prover = { path = "crates/prover", version = "3.0.0" }
-sp1-recursion-compiler = { path = "crates/recursion/compiler", version = "3.0.0" }
-sp1-recursion-core = { path = "crates/recursion/core", version = "3.0.0", default-features = false }
-sp1-recursion-derive = { path = "crates/recursion/derive", version = "3.0.0", default-features = false }
-sp1-recursion-gnark-ffi = { path = "crates/recursion/gnark-ffi", version = "3.0.0", default-features = false }
-sp1-recursion-circuit = { path = "crates/recursion/circuit", version = "3.0.0", default-features = false }
-sp1-sdk = { path = "crates/sdk", version = "3.0.0" }
-sp1-cuda = { path = "crates/cuda", version = "3.0.0" }
-sp1-stark = { path = "crates/stark", version = "3.0.0" }
-sp1-lib = { path = "crates/zkvm/lib", version = "3.0.0", default-features = false }
+sp1-build = { path = "crates/build", version = "=4.0.0-rc.1" }
+sp1-cli = { path = "crates/cli", version = "=4.0.0-rc.1", default-features = false }
+sp1-core-machine = { path = "crates/core/machine", version = "=4.0.0-rc.1" }
+sp1-core-executor = { path = "crates/core/executor", version = "=4.0.0-rc.1" }
+sp1-curves = { path = "crates/curves", version = "=4.0.0-rc.1" }
+sp1-derive = { path = "crates/derive", version = "=4.0.0-rc.1" }
+sp1-eval = { path = "crates/eval", version = "=4.0.0-rc.1" }
+sp1-helper = { path = "crates/helper", version = "=4.0.0-rc.1", default-features = false }
+sp1-primitives = { path = "crates/primitives", version = "=4.0.0-rc.1" }
+sp1-prover = { path = "crates/prover", version = "=4.0.0-rc.1" }
+sp1-recursion-compiler = { path = "crates/recursion/compiler", version = "=4.0.0-rc.1" }
+sp1-recursion-core = { path = "crates/recursion/core", version = "=4.0.0-rc.1", default-features = false }
+sp1-recursion-derive = { path = "crates/recursion/derive", version = "=4.0.0-rc.1", default-features = false }
+sp1-recursion-gnark-ffi = { path = "crates/recursion/gnark-ffi", version = "=4.0.0-rc.1", default-features = false }
+sp1-recursion-circuit = { path = "crates/recursion/circuit", version = "=4.0.0-rc.1", default-features = false }
+sp1-sdk = { path = "crates/sdk", version = "=4.0.0-rc.1" }
+sp1-cuda = { path = "crates/cuda", version = "=4.0.0-rc.1" }
+sp1-stark = { path = "crates/stark", version = "=4.0.0-rc.1" }
+sp1-lib = { path = "crates/zkvm/lib", version = "=4.0.0-rc.1", default-features = false }
# NOTE: The version in this crate is manually set to 3.0.1 right now. When upgrading SP1 versions,
# make sure to update this crate.
-sp1-zkvm = { path = "crates/zkvm/entrypoint", version = "3.0.1", default-features = false }
+sp1-zkvm = { path = "crates/zkvm/entrypoint", version = "=4.0.0-rc.1", default-features = false }
+
+# For testing.
+test-artifacts = { path = "crates/test-artifacts", version = "=4.0.0-rc.1" }
# p3
# p3-air = "0.1.4-succinct"
@@ -138,6 +142,14 @@ p3-bn254-fr = { git = "https://github.com/Plonky3/Plonky3", branch = "sp1-v4" }
# p3-maybe-rayon = { path = "../Plonky3/maybe-rayon" }
# p3-bn254-fr = { path = "../Plonky3/bn254-fr" }
+# misc
+hashbrown = "0.14.5"
+itertools = "0.13.0"
+serde = "1.0.204"
+serde_json = "1.0.132"
+tracing = "0.1.40"
+tracing-subscriber = "0.3.18"
+
[workspace.metadata.typos]
# TODO: Fix in next version since CommitCommitedValuesDigest is retained since it's present in constraints.json
default.extend-ignore-re = [
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 77014462c3..390ecb2573 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -4,7 +4,7 @@ This is a guide with helpful information for developers who want to contribute t
## Getting started
-You can run the test suite in SP1 core by running the following command:
+To build SP1, you must install [Go](https://go.dev/doc/install). You can run the test suite in SP1 core by running the following command:
```bash
cd core
diff --git a/audits/rkm0959.md b/audits/rkm0959.md
index 3fb90318af..2c09f508d5 100644
--- a/audits/rkm0959.md
+++ b/audits/rkm0959.md
@@ -393,7 +393,7 @@ this passes each core verification, and since the RecursionPublicValue of proof
- shard 1, 2's committed_value_digest = `0`
- shard 3, 4's committed_value_digest = `x`
-this passes each core verification, as proof #2 thinks shard 3 is its "first" shard - so it actually thinks that the `committed_value_digest` didn't change. This means that the whole "no cpu chip means `commited_value_digest` equal" thing actually just passes. Then, in the compress verification, we'll just see the committed_value_digest go from `0` to `x`, which is also completely fine. However, the committed_value_digest will go `0, 0, x, x`, where the change occurs on a shard without cpu chip - which isn't supposed to happen.
+this passes each core verification, as proof #2 thinks shard 3 is its "first" shard - so it actually thinks that the `committed_value_digest` didn't change. This means that the whole "no cpu chip means `committed_value_digest` equal" thing actually just passes. Then, in the compress verification, we'll just see the committed_value_digest go from `0` to `x`, which is also completely fine. However, the committed_value_digest will go `0, 0, x, x`, where the change occurs on a shard without cpu chip - which isn't supposed to happen.
While this is a slight incompatibility, the main invariant (if nonzero, public digest can only be one non-zero value) is preserved. Therefore, we did not fix this observation.
diff --git a/book/SUMMARY.md b/book/SUMMARY.md
index 55ec23f628..4bde9eef98 100644
--- a/book/SUMMARY.md
+++ b/book/SUMMARY.md
@@ -72,6 +72,6 @@
- [Usage in CI](./developers/usage-in-ci.md)
-- [RV32IM Specification](./developers/rv32im-specification.md)
+- [RV32IM Deviations](./developers/rv32im-deviations.md)
- [Building Circuit Artifacts](./developers/building-circuit-artifacts.md)
diff --git a/book/developers/rv32im-deviations.md b/book/developers/rv32im-deviations.md
new file mode 100644
index 0000000000..e28f294450
--- /dev/null
+++ b/book/developers/rv32im-deviations.md
@@ -0,0 +1,27 @@
+# RV32IM Deviations
+
+**SP1 does not conform exactly to the official RISC-V RV32IM specification.** Instead, it includes
+several minor modifications tailored to make it more suitable for use in proving systems. These
+deviations are outlined below:
+
+- Addresses `0x0` to `0x20` are reserved for registers. Writing to these addresses will modify
+ register state and cause divergent behavior from the RISC-V specification.
+- Memory access is only valid for addresses `0x20, 0x78000000`. Writing to any other addresses
+ will result in undefined behavior. The heap allocator is also constrained to these addresses.
+- Memory access must be "aligned". The alignment is automatically enforced by all programs compiled
+ through the official SP1 RISC-V toolchain.
+ - LW/SW memory access must be word aligned.
+ - LH/LHU/SH memory access must be half-word aligned.
+ - LW/SW memory access must be word aligned.
+ - LH/LHU/SH memory access must be half-word aligned.
+- The ECALL instruction is used for system calls and precompiles. Only valid syscall IDs should be called, and only using the specific convention of loading the ID into register T0 and arguments into registers A0 and A1. If the arguments are addresses, they must be word-aligned. Failure to follow this convention can result in undefined behavior. Correct usages can be found in the `sp1_zkvm` and `sp1_lib` crates.
+
+## Security Considerations
+
+While the deviations from the RISC-V specification could theoretically be exploited to cause
+divergent execution, such scenarios require a deliberately malicious program. The SP1 security
+model assumes that programs are honestly compiled, as malicious bytecode could otherwise exploit
+program execution and I/O.
+
+These security concerns regarding divergent execution have been reviewed and discussed with external
+security researchers, including rkm0959, Zellic, samczsun, and others.
\ No newline at end of file
diff --git a/book/developers/rv32im-specification.md b/book/developers/rv32im-specification.md
deleted file mode 100644
index 84e8aa7584..0000000000
--- a/book/developers/rv32im-specification.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# RV32IM Specification
-
-SP1 implements the RISC-V RV32IM instruction set with some implementation details that make it more suitable for proving.
-
-- LW/SW memory access must be word aligned.
-- LH/LHU/SH memory access must be half-word aligned.
-- Memory access is only valid for addresses `0x20, 0x78000000`. Accessing addresses outside of this range will result in undefined behavior. The global heap allocator in `sp1_zkvm` will panic if memory exceeds this range.
-- The ECALL instruction is used for system calls and precompiles. Only valid syscall IDs should be called, and only using the specific convention of loading the ID into register T0 and arguments into registers A0 and A1. If the arguments are addresses, they must be word-aligned. Failure to follow this convention can result in undefined behavior. Correct usages can be found in the `sp1_zkvm` and `sp1_lib` crates.
diff --git a/book/generating-proofs/basics.md b/book/generating-proofs/basics.md
index 85273d96ba..7bde99bbc1 100644
--- a/book/generating-proofs/basics.md
+++ b/book/generating-proofs/basics.md
@@ -13,7 +13,8 @@ To make this more concrete, let's walk through a simple example of generating a
You can run the above script in the `script` directory with `RUST_LOG=info cargo run --release`. Note that running the above script will generate a proof locally.
-WARNING: Local proving often is much slower than the prover network and for certain proof types (e.g. Groth16, PLONK) require a significant amount of RAM and will likely not work on a laptop.
+WARNING: Local proving often is much slower than the prover network and for certain proof types (e.g. Groth16, PLONK) require a
+significant amount of RAM. You might only be able to generate proofs for small inputs locally.
We recommend using the [prover network](./prover-network.md) to generate proofs. Read more about the [recommended workflow](./recommended-workflow.md) for developing with SP1.
diff --git a/book/generating-proofs/prover-network/versions.md b/book/generating-proofs/prover-network/versions.md
index 4190b713fe..3060a610ad 100644
--- a/book/generating-proofs/prover-network/versions.md
+++ b/book/generating-proofs/prover-network/versions.md
@@ -4,8 +4,7 @@ The prover network currently only supports specific versions of SP1:
| Version | Description |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| v2.X.X | Audited, production ready version. |
-| v3.X.X | Pre-release version with enhanced performance, currently being audited. **Recommended for benchmarking or testing, not recommended for production use.** |
+| v3.X.X | V3 Release. Latest performant & production ready version. |
`X` denotes that any minor and patch version is supported (e.g. `v2.1.0`, `v2.1.1`).
diff --git a/book/getting-started/hardware-requirements.md b/book/getting-started/hardware-requirements.md
index 828ea96080..3877d22e84 100644
--- a/book/getting-started/hardware-requirements.md
+++ b/book/getting-started/hardware-requirements.md
@@ -31,7 +31,9 @@ which can be parallelized with multiple cores.
Our prover requires keeping large matrices (i.e., traces) in memory to generate the proofs. Certain steps of the prover
have a minimum memory requirement, meaning that if you have less than this amount of memory, the process will OOM.
-This effect is most noticeable when using the Groth16 or PLONK provers.
+This effect is most noticeable when using the Groth16 or PLONK provers. If you're running the Groth16 or Plonk provers locally
+on Mac or Windows using docker, you might need to increase the memory limit for
+[docker desktop](https://docs.docker.com/desktop/settings-and-maintenance/settings/#resources).
### Disk
diff --git a/book/getting-started/install.md b/book/getting-started/install.md
index e58b9a624e..7c1a4ae85b 100644
--- a/book/getting-started/install.md
+++ b/book/getting-started/install.md
@@ -91,7 +91,7 @@ git clone git@github.com:succinctlabs/sp1.git
cd sp1
cd crates
cd cli
-cargo install --locked --path .
+cargo install --locked --force --path .
cd ~
cargo prove build-toolchain
```
diff --git a/book/getting-started/quickstart.md b/book/getting-started/quickstart.md
index 824ddbf857..76f1356b3d 100644
--- a/book/getting-started/quickstart.md
+++ b/book/getting-started/quickstart.md
@@ -34,8 +34,6 @@ Your new project will have the following structure (ignoring the `contracts` fol
├── program
│ ├── Cargo.lock
│ ├── Cargo.toml
-│ ├── elf
-│ │ └── riscv32im-succinct-zkvm-elf
│ └── src
│ └── main.rs
├── rust-toolchain
@@ -66,7 +64,7 @@ Before we can run the program inside the zkVM, it must be compiled to a RISC-V e
cd program && cargo prove build
```
-which will output the compiled ELF to the file `program/elf/riscv32im-succinct-zkvm-elf`.
+which will generate an ELF file under `target/elf-compilation`.
Note: the `build.rs` file in the `script` directory will use run the above command automatically to build the ELF, meaning you don't have to manually run `cargo prove build` every time you make a change to the program!
diff --git a/book/verification/off-chain-verification.md b/book/verification/off-chain-verification.md
index 3dd4bc601f..100e554eb4 100644
--- a/book/verification/off-chain-verification.md
+++ b/book/verification/off-chain-verification.md
@@ -4,7 +4,7 @@
You can verify SP1 Groth16 and Plonk proofs in `no_std` environments with [`sp1-verifier`](https://docs.rs/sp1-verifier/latest/sp1_verifier/).
-`sp1-verifier` is also patched to verify Groth16 and Plonk proofs within the SP1 ZKVM, using
+`sp1-verifier` is also patched to verify Groth16 and Plonk proofs within the SP1 zkVM, using
[bn254](https://blog.succinct.xyz/succinctshipsprecompiles/) precompiles. For an example of this, see
the [Groth16 Example](https://github.com/succinctlabs/sp1/tree/main/examples/groth16/).
@@ -43,6 +43,45 @@ Here, the proof, public inputs, and vkey hash are read from stdin. See the follo
> Note that the SP1 SDK itself is *not* `no_std` compatible.
+### Advanced: `verify_gnark_proof`
+
+`sp1-verifier` also exposes [`Groth16Verifier::verify_gnark_proof`](https://docs.rs/sp1-verifier/latest/sp1_verifier/struct.Groth16Verifier.html#method.verify_gnark_proof) and [`PlonkVerifier::verify_gnark_proof`](https://docs.rs/sp1-verifier/latest/sp1_verifier/struct.PlonkVerifier.html#method.verify_gnark_proof),
+which verifies any Groth16 or Plonk proof from Gnark. This is especially useful for verifying custom Groth16 and Plonk proofs
+efficiently in the SP1 zkVM.
+
+The following snippet demonstrates how you might serialize a Gnark proof in a way that `sp1-verifier` can use.
+
+```go
+// Write the verifier key.
+vkFile, err := os.Create("vk.bin")
+if err != nil {
+ panic(err)
+}
+defer vkFile.Close()
+
+// Here, `vk` is a `groth16_bn254.VerifyingKey` or `plonk_bn254.VerifyingKey`.
+_, err = vk.WriteTo(vkFile)
+if err != nil {
+ panic(err)
+}
+
+// Write the proof.
+proofFile, err := os.Create("proof.bin")
+if err != nil {
+ panic(err)
+}
+defer proofFile.Close()
+
+// Here, `proof` is a `groth16_bn254.Proof` or `plonk_bn254.Proof`.
+_, err = proof.WriteTo(proofFile)
+if err != nil {
+ panic(err)
+}
+```
+
+Public values are serialized as big-endian `Fr` values. The default Gnark serialization will work
+out of the box.
+
## Wasm Verification
The [`example-sp1-wasm-verifier`](https://github.com/succinctlabs/example-sp1-wasm-verifier) demonstrates how to
diff --git a/book/verification/onchain/getting-started.md b/book/verification/onchain/getting-started.md
index 8519d620a8..715b100d58 100644
--- a/book/verification/onchain/getting-started.md
+++ b/book/verification/onchain/getting-started.md
@@ -14,7 +14,8 @@ By default, the proofs generated by SP1 are not verifiable onchain, as they are
> WARNING: The Groth16 and PLONK provers are only guaranteed to work on official releases of SP1. To
> use Groth16 or PLONK proving & verification locally, ensure that you have Docker installed and have
-> at least 128GB of RAM.
+> at least 32GB of RAM. Note that you might need to increase the memory limit for
+> [docker desktop](https://docs.docker.com/desktop/settings-and-maintenance/settings/#resources) if you're running on Mac.
### Example
diff --git a/book/verification/supported-versions.md b/book/verification/supported-versions.md
new file mode 100644
index 0000000000..b79555c32f
--- /dev/null
+++ b/book/verification/supported-versions.md
@@ -0,0 +1 @@
+# Supported Versions
diff --git a/book/writing-programs/compiling.md b/book/writing-programs/compiling.md
index 6a1fdc56b4..297facb547 100644
--- a/book/writing-programs/compiling.md
+++ b/book/writing-programs/compiling.md
@@ -14,7 +14,7 @@ To build a program while developing, simply run the following command in the cra
cargo prove build
```
-This will compile the ELF that can be executed in the zkVM and put it in the file `elf/riscv32im-succinct-zkvm-elf`. The output from the command will look something like this:
+This will compile the ELF that can be executed in the zkVM. The output from the command will look something like this:
```bash
[sp1] Compiling version_check v0.9.4
diff --git a/crates/build/src/build.rs b/crates/build/src/build.rs
index b19207d406..37ee7392ac 100644
--- a/crates/build/src/build.rs
+++ b/crates/build/src/build.rs
@@ -5,7 +5,7 @@ use cargo_metadata::camino::Utf8PathBuf;
use crate::{
command::{docker::create_docker_command, local::create_local_command, utils::execute_command},
- utils::{cargo_rerun_if_changed, copy_elf_to_output_dir, current_datetime},
+ utils::{cargo_rerun_if_changed, current_datetime},
BuildArgs, BUILD_TARGET, HELPER_TARGET_SUBDIR,
};
@@ -48,11 +48,7 @@ pub fn execute_build_program(
let target_elf_paths = generate_elf_paths(&program_metadata, Some(args))?;
- // Temporary backward compatibility with the deprecated behavior of copying the ELF file.
- // TODO: add option to turn off this behavior
- if target_elf_paths.len() == 1 {
- copy_elf_to_output_dir(args, &program_metadata, &target_elf_paths[0].1)?;
- }
+ print_elf_paths_cargo_directives(&target_elf_paths);
Ok(target_elf_paths)
}
@@ -73,7 +69,10 @@ pub(crate) fn build_program_internal(path: &str, args: Option) {
.unwrap_or(false);
if skip_program_build {
// Still need to set ELF env vars even if build is skipped.
- generate_elf_paths(&metadata, args.as_ref()).expect("failed to collect target ELF paths");
+ let target_elf_paths = generate_elf_paths(&metadata, args.as_ref())
+ .expect("failed to collect target ELF paths");
+
+ print_elf_paths_cargo_directives(&target_elf_paths);
println!(
"cargo:warning=Build skipped for {} at {} due to SP1_SKIP_PROGRAM_BUILD flag",
@@ -94,7 +93,10 @@ pub(crate) fn build_program_internal(path: &str, args: Option) {
.unwrap_or(false);
if is_clippy_driver {
// Still need to set ELF env vars even if build is skipped.
- generate_elf_paths(&metadata, args.as_ref()).expect("failed to collect target ELF paths");
+ let target_elf_paths = generate_elf_paths(&metadata, args.as_ref())
+ .expect("failed to collect target ELF paths");
+
+ print_elf_paths_cargo_directives(&target_elf_paths);
println!("cargo:warning=Skipping build due to clippy invocation.");
return;
@@ -113,19 +115,39 @@ pub(crate) fn build_program_internal(path: &str, args: Option) {
println!("cargo:warning={} built at {}", root_package_name, current_datetime());
}
-/// Collects the list of targets that would be built and their output ELF file paths. Also prints
-/// cargo directives setting relevant `SP1_ELF_` environment variables.
-fn generate_elf_paths(
+/// Collects the list of targets that would be built and their output ELF file paths.
+pub fn generate_elf_paths(
metadata: &cargo_metadata::Metadata,
args: Option<&BuildArgs>,
) -> Result> {
let mut target_elf_paths = vec![];
+ let packages_to_iterate = if let Some(args) = args {
+ if !args.packages.is_empty() {
+ args.packages
+ .iter()
+ .map(|wanted_package| {
+ metadata
+ .packages
+ .iter()
+ .find(|p| p.name == *wanted_package)
+ .ok_or_else(|| {
+ anyhow::anyhow!("cannot find package named {}", wanted_package)
+ })
+ .map(|p| p.id.clone())
+ })
+ .collect::>>()?
+ } else {
+ metadata.workspace_default_members.to_vec()
+ }
+ } else {
+ metadata.workspace_default_members.to_vec()
+ };
- for program_crate in metadata.workspace_default_members.iter() {
+ for program_crate in packages_to_iterate {
let program = metadata
.packages
.iter()
- .find(|p| &p.id == program_crate)
+ .find(|p| p.id == program_crate)
.ok_or_else(|| anyhow::anyhow!("cannot find package for {}", program_crate))?;
for bin_target in program.targets.iter().filter(|t| {
@@ -133,7 +155,7 @@ fn generate_elf_paths(
}) {
// Filter out irrelevant targets if `--bin` is used.
if let Some(args) = args {
- if !args.binary.is_empty() && bin_target.name != args.binary {
+ if !args.binaries.is_empty() && !args.binaries.contains(&bin_target.name) {
continue;
}
}
@@ -149,9 +171,12 @@ fn generate_elf_paths(
}
}
+ Ok(target_elf_paths)
+}
+
+/// Prints cargo directives setting relevant `SP1_ELF_` environment variables.
+fn print_elf_paths_cargo_directives(target_elf_paths: &[(String, Utf8PathBuf)]) {
for (target_name, elf_path) in target_elf_paths.iter() {
println!("cargo:rustc-env=SP1_ELF_{}={}", target_name, elf_path);
}
-
- Ok(target_elf_paths)
}
diff --git a/crates/build/src/command/utils.rs b/crates/build/src/command/utils.rs
index 7eef9dc9a4..ba5ec28532 100644
--- a/crates/build/src/command/utils.rs
+++ b/crates/build/src/command/utils.rs
@@ -22,9 +22,14 @@ pub(crate) fn get_program_build_args(args: &BuildArgs) -> Vec {
build_args.push("-Ztrim-paths".to_string());
- if !args.binary.is_empty() {
+ for p in &args.packages {
+ build_args.push("-p".to_string());
+ build_args.push(p.to_string());
+ }
+
+ for b in &args.binaries {
build_args.push("--bin".to_string());
- build_args.push(args.binary.clone());
+ build_args.push(b.to_string());
}
if !args.features.is_empty() {
diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs
index 17b18602fc..1dbbec1347 100644
--- a/crates/build/src/lib.rs
+++ b/crates/build/src/lib.rs
@@ -2,7 +2,7 @@ mod build;
mod command;
mod utils;
use build::build_program_internal;
-pub use build::execute_build_program;
+pub use build::{execute_build_program, generate_elf_paths};
use clap::Parser;
@@ -50,14 +50,22 @@ pub struct BuildArgs {
pub ignore_rust_version: bool,
#[clap(long, action, help = "Assert that `Cargo.lock` will remain unchanged")]
pub locked: bool,
+ #[clap(
+ short,
+ long,
+ action,
+ help = "Build only the specified packages",
+ num_args = 1..
+ )]
+ pub packages: Vec,
#[clap(
alias = "bin",
long,
action,
- help = "Build only the specified binary",
- default_value = ""
+ help = "Build only the specified binaries",
+ num_args = 1..
)]
- pub binary: String,
+ pub binaries: Vec,
#[clap(long, action, help = "ELF binary name", default_value = "")]
pub elf_name: String,
#[clap(
@@ -79,7 +87,8 @@ impl Default for BuildArgs {
features: vec![],
rustflags: vec![],
ignore_rust_version: false,
- binary: "".to_string(),
+ packages: vec![],
+ binaries: vec![],
elf_name: "".to_string(),
output_directory: DEFAULT_OUTPUT_DIR.to_string(),
locked: false,
@@ -117,3 +126,19 @@ pub fn build_program(path: &str) {
pub fn build_program_with_args(path: &str, args: BuildArgs) {
build_program_internal(path, Some(args))
}
+
+/// Returns the raw ELF bytes by the zkVM program target name.
+///
+/// Note that this only works when using `sp1_build::build_program` or
+/// `sp1_build::build_program_with_args` in a build script.
+///
+/// By default, the program target name is the same as the program crate name. However, this might
+/// not be the case for non-standard project structures. For example, placing the entrypoint source
+/// file at `src/bin/my_entry.rs` would result in the program target being named `my_entry`, in
+/// which case the invocation should be `include_elf!("my_entry")` instead.
+#[macro_export]
+macro_rules! include_elf {
+ ($arg:tt) => {{
+ include_bytes!(env!(concat!("SP1_ELF_", $arg)))
+ }};
+}
diff --git a/crates/build/src/utils.rs b/crates/build/src/utils.rs
index ac5dd03c19..032692808b 100644
--- a/crates/build/src/utils.rs
+++ b/crates/build/src/utils.rs
@@ -1,40 +1,8 @@
-use std::{fs, path::Path};
+use std::path::Path;
-use anyhow::Result;
-use cargo_metadata::{camino::Utf8PathBuf, Metadata};
+use cargo_metadata::Metadata;
use chrono::Local;
-use crate::{BuildArgs, BUILD_TARGET};
-
-/// Copy the ELF to the specified output directory.
-pub(crate) fn copy_elf_to_output_dir(
- args: &BuildArgs,
- program_metadata: &cargo_metadata::Metadata,
- elf_path: &Utf8PathBuf,
-) -> Result {
- // The order of precedence for the ELF name is:
- // 1. --elf_name flag
- // 2. --binary flag + -elf suffix (defaults to riscv32im-succinct-zkvm-elf)
- let elf_name = if !args.elf_name.is_empty() {
- args.elf_name.clone()
- } else if !args.binary.is_empty() {
- // TODO: In the future, change this to default to the package name. Will require updating
- // docs and examples.
- args.binary.clone()
- } else {
- BUILD_TARGET.to_string()
- };
-
- let elf_dir = program_metadata.target_directory.parent().unwrap().join(&args.output_directory);
- fs::create_dir_all(&elf_dir)?;
- let result_elf_path = elf_dir.join(elf_name);
-
- // Copy the ELF to the specified output directory.
- fs::copy(elf_path, &result_elf_path)?;
-
- Ok(result_elf_path)
-}
-
pub(crate) fn current_datetime() -> String {
let now = Local::now();
now.format("%Y-%m-%d %H:%M:%S").to_string()
diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml
index 1e6bd0e088..cf2e8cb4b2 100644
--- a/crates/cli/Cargo.toml
+++ b/crates/cli/Cargo.toml
@@ -32,7 +32,7 @@ indicatif = "0.17.8"
tokio = { version = "1", features = ["full"] }
dirs = "5.0"
rand = "0.8"
-serde_json = "1.0.121"
+serde_json = { workspace = true }
yansi = "1.0.1"
hex = "0.4.3"
anstyle = "1.0.8"
@@ -43,3 +43,4 @@ regex = "1.5.4"
prettytable-rs = "0.10"
textwrap = "0.16.0"
ctrlc = "3.4.2"
+cargo_metadata = "0.18.1"
\ No newline at end of file
diff --git a/crates/cli/README.md b/crates/cli/README.md
index 30e8f31596..5bdd852918 100644
--- a/crates/cli/README.md
+++ b/crates/cli/README.md
@@ -21,7 +21,7 @@ cargo run --bin cargo-prove -- prove trace --elf <...> --trace <...>
You can install the CLI locally from source by running the following command:
```bash
-cargo install --locked --path .
+cargo install --locked --force --path .
```
### Running the CLI after installing
diff --git a/crates/cli/src/bin/cargo-prove.rs b/crates/cli/src/bin/cargo-prove.rs
index 56f452e708..e2b87d44bd 100644
--- a/crates/cli/src/bin/cargo-prove.rs
+++ b/crates/cli/src/bin/cargo-prove.rs
@@ -3,8 +3,7 @@ use clap::{Parser, Subcommand};
use sp1_cli::{
commands::{
build::BuildCmd, build_toolchain::BuildToolchainCmd,
- install_toolchain::InstallToolchainCmd, new::NewCmd, prove::ProveCmd, trace::TraceCmd,
- vkey::VkeyCmd,
+ install_toolchain::InstallToolchainCmd, new::NewCmd, trace::TraceCmd, vkey::VkeyCmd,
},
SP1_VERSION_MESSAGE,
};
@@ -19,17 +18,13 @@ pub enum Cargo {
#[command(author, about, long_about = None, args_conflicts_with_subcommands = true, version = SP1_VERSION_MESSAGE)]
pub struct ProveCli {
#[clap(subcommand)]
- pub command: Option,
-
- #[clap(flatten)]
- pub prove: ProveCmd,
+ pub command: ProveCliCommands,
}
#[derive(Subcommand)]
pub enum ProveCliCommands {
New(NewCmd),
Build(BuildCmd),
- Prove(ProveCmd),
BuildToolchain(BuildToolchainCmd),
InstallToolchain(InstallToolchainCmd),
Trace(TraceCmd),
@@ -38,11 +33,10 @@ pub enum ProveCliCommands {
fn main() -> Result<()> {
let Cargo::Prove(args) = Cargo::parse();
- let command = args.command.unwrap_or(ProveCliCommands::Prove(args.prove));
- match command {
+
+ match args.command {
ProveCliCommands::New(cmd) => cmd.run(),
ProveCliCommands::Build(cmd) => cmd.run(),
- ProveCliCommands::Prove(cmd) => cmd.run(),
ProveCliCommands::BuildToolchain(cmd) => cmd.run(),
ProveCliCommands::InstallToolchain(cmd) => cmd.run(),
ProveCliCommands::Trace(cmd) => cmd.run(),
diff --git a/crates/cli/src/commands/build_toolchain.rs b/crates/cli/src/commands/build_toolchain.rs
index 97f1aae009..0e13d56cb5 100644
--- a/crates/cli/src/commands/build_toolchain.rs
+++ b/crates/cli/src/commands/build_toolchain.rs
@@ -64,7 +64,8 @@ impl BuildToolchainCmd {
std::fs::write(&config_file, config_toml)
.with_context(|| format!("while writing configuration to {:?}", config_file))?;
- // Work around target sanity check added in rust-lang/rust@09c076810cb7649e5817f316215010d49e78e8d7.
+ // Work around target sanity check added in
+ // rust-lang/rust@09c076810cb7649e5817f316215010d49e78e8d7.
let temp_dir = std::env::temp_dir().join("rustc-targets");
if !temp_dir.exists() {
std::fs::create_dir_all(&temp_dir)?;
diff --git a/crates/cli/src/commands/mod.rs b/crates/cli/src/commands/mod.rs
index af62dcf36e..fc6eb6a5ac 100644
--- a/crates/cli/src/commands/mod.rs
+++ b/crates/cli/src/commands/mod.rs
@@ -2,6 +2,5 @@ pub mod build;
pub mod build_toolchain;
pub mod install_toolchain;
pub mod new;
-pub mod prove;
pub mod trace;
pub mod vkey;
diff --git a/crates/cli/src/commands/prove.rs b/crates/cli/src/commands/prove.rs
deleted file mode 100644
index 747752dad4..0000000000
--- a/crates/cli/src/commands/prove.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-use anstyle::*;
-use anyhow::Result;
-use clap::Parser;
-use sp1_build::{execute_build_program, BuildArgs};
-use sp1_core_machine::{
- io::SP1Stdin,
- utils::{setup_logger, setup_tracer},
-};
-use sp1_sdk::ProverClient;
-use std::{env, fs::File, io::Read, path::PathBuf, str::FromStr, time::Instant};
-
-use crate::util::{elapsed, write_status};
-
-#[derive(Debug, Clone)]
-enum Input {
- FilePath(PathBuf),
- HexBytes(Vec),
-}
-
-fn is_valid_hex_string(s: &str) -> bool {
- if s.len() % 2 != 0 {
- return false;
- }
- // All hex digits with optional 0x prefix
- s.starts_with("0x") && s[2..].chars().all(|c| c.is_ascii_hexdigit())
- || s.chars().all(|c| c.is_ascii_hexdigit())
-}
-
-impl FromStr for Input {
- type Err = String;
-
- fn from_str(s: &str) -> Result {
- if is_valid_hex_string(s) {
- // Remove 0x prefix if present
- let s = if s.starts_with("0x") { s.strip_prefix("0x").unwrap() } else { s };
- if s.is_empty() {
- return Ok(Input::HexBytes(Vec::new()));
- }
- if !s.chars().all(|c| c.is_ascii_hexdigit()) {
- return Err("Invalid hex string.".to_string());
- }
- let bytes = hex::decode(s).map_err(|e| e.to_string())?;
- Ok(Input::HexBytes(bytes))
- } else if PathBuf::from(s).exists() {
- Ok(Input::FilePath(PathBuf::from(s)))
- } else {
- Err("Input must be a valid file path or hex string.".to_string())
- }
- }
-}
-
-#[derive(Parser)]
-#[command(name = "prove", about = "(default) Build and prove a program")]
-pub struct ProveCmd {
- #[clap(long, value_parser)]
- input: Option ,
-
- #[clap(long, action)]
- output: Option,
-
- #[clap(long, action)]
- profile: bool,
-
- #[clap(long, action)]
- verbose: bool,
-
- #[clap(flatten)]
- build_args: BuildArgs,
-}
-
-impl ProveCmd {
- pub fn run(&self) -> Result<()> {
- let elf_paths = execute_build_program(&self.build_args, None)?;
-
- if !self.profile {
- match env::var("RUST_LOG") {
- Ok(_) => {}
- Err(_) => env::set_var("RUST_LOG", "info"),
- }
- setup_logger();
- } else {
- match env::var("RUST_TRACER") {
- Ok(_) => {}
- Err(_) => env::set_var("RUST_TRACER", "info"),
- }
- setup_tracer();
- }
-
- // The command predates multi-target build support. This allows the command to continue to
- // work when only one package is built, preserving backward compatibility.
- let elf_path = if elf_paths.len() == 1 {
- elf_paths[0].1.to_owned()
- } else {
- anyhow::bail!("the prove command does not work with multi-target builds");
- };
-
- let mut elf = Vec::new();
- File::open(elf_path.as_path().as_str())
- .expect("failed to open input file")
- .read_to_end(&mut elf)
- .expect("failed to read from input file");
-
- let mut stdin = SP1Stdin::new();
- if let Some(ref input) = self.input {
- match input {
- Input::FilePath(ref path) => {
- let mut file = File::open(path).expect("failed to open input file");
- let mut bytes = Vec::new();
- file.read_to_end(&mut bytes)?;
- stdin.write_slice(&bytes);
- }
- Input::HexBytes(ref bytes) => {
- stdin.write_slice(bytes);
- }
- }
- }
-
- let start_time = Instant::now();
- let client = ProverClient::new();
- let (pk, _) = client.setup(&elf);
- let proof = client.prove(&pk, stdin).run().unwrap();
-
- if let Some(ref path) = self.output {
- proof.save(path.to_str().unwrap()).expect("failed to save proof");
- }
-
- let elapsed = elapsed(start_time.elapsed());
- let green = AnsiColor::Green.on_default().effects(Effects::BOLD);
- write_status(&green, "Finished", format!("proving in {}", elapsed).as_str());
-
- Ok(())
- }
-}
diff --git a/crates/cli/src/commands/vkey.rs b/crates/cli/src/commands/vkey.rs
index a8aeb1c183..734b470970 100644
--- a/crates/cli/src/commands/vkey.rs
+++ b/crates/cli/src/commands/vkey.rs
@@ -1,31 +1,63 @@
-use std::fs::File;
+use std::{fs::File, io::Read};
use anyhow::Result;
-use clap::Parser;
+use clap::{Args, Parser};
+use sp1_build::{generate_elf_paths, BuildArgs};
use sp1_sdk::{HashableKey, ProverClient};
-use std::io::Read;
#[derive(Parser)]
#[command(name = "vkey", about = "View the verification key hash for a program.")]
pub struct VkeyCmd {
/// Path to the ELF.
- #[arg(long, required = true)]
- elf: String,
+ #[clap(flatten)]
+ elf: Elf,
+}
+
+#[derive(Debug, Clone, Args)]
+#[group(required = true, multiple = false)]
+pub struct Elf {
+ /// The path to the ELF file
+ #[arg(long = "elf")]
+ path: Option,
+ /// The crate used to generate the ELF file
+ #[arg(long)]
+ program: Option,
}
impl VkeyCmd {
pub fn run(&self) -> Result<()> {
- // Read the elf file contents
- let mut file = File::open(self.elf.clone()).unwrap();
- let mut elf = Vec::new();
- file.read_to_end(&mut elf).unwrap();
+ let elf_paths = if let Some(path) = &self.elf.path {
+ vec![(None, path.clone())]
+ } else if let Some(program) = &self.elf.program {
+ let metadata_cmd = cargo_metadata::MetadataCommand::new();
+ let metadata = metadata_cmd.exec()?;
+ let build_args = BuildArgs { packages: vec![program.clone()], ..Default::default() };
+
+ generate_elf_paths(&metadata, Some(&build_args))?
+ .into_iter()
+ .map(|(target, path)| (Some(target), path.to_string()))
+ .collect()
+ } else {
+ unreachable!()
+ };
+
+ for (target, elf_path) in elf_paths {
+ // Read the elf file contents
+ let mut file = File::open(elf_path)?;
+ let mut elf = Vec::new();
+ file.read_to_end(&mut elf)?;
- // Get the verification key
- let prover = ProverClient::new();
- let (_, vk) = prover.setup(&elf);
+ // Get the verification key
+ let prover = ProverClient::new();
+ let (_, vk) = prover.setup(&elf);
- // Print the verification key hash
- println!("Verification Key Hash:\n{}", vk.vk.bytes32());
+ // Print the verification key hash
+ if let Some(target) = target {
+ println!("Verification Key Hash for '{target}':\n{}", vk.vk.bytes32());
+ } else {
+ println!("Verification Key Hash:\n{}", vk.vk.bytes32());
+ }
+ }
Ok(())
}
diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs
index c9762921be..9e717aadae 100644
--- a/crates/cli/src/lib.rs
+++ b/crates/cli/src/lib.rs
@@ -1,5 +1,4 @@
pub mod commands;
-mod util;
use anyhow::{Context, Result};
use reqwest::Client;
@@ -48,7 +47,14 @@ pub fn is_supported_target() -> bool {
}
pub fn get_target() -> String {
- target_lexicon::HOST.to_string()
+ let mut target: target_lexicon::Triple = target_lexicon::HOST;
+
+ // We don't want to operate on the musl toolchain, even if the CLI was compiled with musl
+ if target.environment == target_lexicon::Environment::Musl {
+ target.environment = target_lexicon::Environment::Gnu;
+ }
+
+ target.to_string()
}
pub async fn get_toolchain_download_url(client: &Client, target: String) -> String {
diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs
deleted file mode 100644
index 6993d74403..0000000000
--- a/crates/cli/src/util.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use std::{fmt::Display, time::Duration};
-
-pub(crate) fn write_status(style: &dyn Display, status: &str, msg: &str) {
- println!("{style}{status:>12}{style:#} {msg}");
-}
-
-pub(crate) fn elapsed(duration: Duration) -> String {
- let secs = duration.as_secs();
-
- if secs >= 60 {
- format!("{}m {:02}s", secs / 60, secs % 60)
- } else {
- format!("{}.{:02}s", secs, duration.subsec_nanos() / 10_000_000)
- }
-}
diff --git a/crates/core/executor/Cargo.toml b/crates/core/executor/Cargo.toml
index 273b12aa4c..2cbf03a117 100644
--- a/crates/core/executor/Cargo.toml
+++ b/crates/core/executor/Cargo.toml
@@ -20,19 +20,19 @@ p3-field = { workspace = true }
p3-maybe-rayon = { workspace = true, features = ["parallel"] }
# misc
-serde = { version = "1.0.205", features = ["derive", "rc"] }
+serde = { workspace = true, features = ["derive", "rc"] }
elf = "0.7.4"
rrs_lib = { package = "rrs-succinct", version = "0.1.0" }
eyre = "0.6.12"
bincode = "1.3.3"
-hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] }
-itertools = "0.13.0"
+hashbrown = { workspace = true, features = ["serde", "inline-more"] }
+itertools = { workspace = true }
rand = "0.8.5"
num = { version = "0.4.3" }
typenum = "1.17.0"
nohash-hasher = "0.2.0"
thiserror = "1.0.63"
-tracing = "0.1.40"
+tracing = { workspace = true }
strum_macros = "0.26.4"
strum = { version = "0.26.3", features = ["derive"] }
log = "0.4.22"
@@ -41,10 +41,11 @@ bytemuck = "1.16.3"
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
vec_map = { version = "0.8.2", features = ["serde"] }
enum-map = { version = "2.7.3", features = ["serde"] }
+test-artifacts = { workspace = true, optional = true }
[dev-dependencies]
-sp1-zkvm = { workspace = true }
+sp1-zkvm = { workspace = true, features = ["lib"] }
[features]
-programs = []
+programs = ["dep:test-artifacts"]
bigint-rug = ["sp1-curves/bigint-rug"]
diff --git a/crates/core/executor/src/context.rs b/crates/core/executor/src/context.rs
index 9585c6b851..0d6c05b170 100644
--- a/crates/core/executor/src/context.rs
+++ b/crates/core/executor/src/context.rs
@@ -21,6 +21,9 @@ pub struct SP1Context<'a> {
/// The maximum number of cpu cycles to use for execution.
pub max_cycles: Option,
+
+ /// Skip deferred proof verification.
+ pub skip_deferred_proof_verification: bool,
}
/// A builder for [`SP1Context`].
@@ -30,6 +33,7 @@ pub struct SP1ContextBuilder<'a> {
hook_registry_entries: Vec<(u32, BoxedHook<'a>)>,
subproof_verifier: Option>,
max_cycles: Option,
+ skip_deferred_proof_verification: bool,
}
impl<'a> SP1Context<'a> {
@@ -68,7 +72,13 @@ impl<'a> SP1ContextBuilder<'a> {
});
let subproof_verifier = take(&mut self.subproof_verifier);
let cycle_limit = take(&mut self.max_cycles);
- SP1Context { hook_registry, subproof_verifier, max_cycles: cycle_limit }
+ let skip_deferred_proof_verification = take(&mut self.skip_deferred_proof_verification);
+ SP1Context {
+ hook_registry,
+ subproof_verifier,
+ max_cycles: cycle_limit,
+ skip_deferred_proof_verification,
+ }
}
/// Add a runtime [Hook](super::Hook) into the context.
@@ -110,6 +120,12 @@ impl<'a> SP1ContextBuilder<'a> {
self.max_cycles = Some(max_cycles);
self
}
+
+ /// Set the skip deferred proof verification flag.
+ pub fn set_skip_deferred_proof_verification(&mut self, skip: bool) -> &mut Self {
+ self.skip_deferred_proof_verification = skip;
+ self
+ }
}
#[cfg(test)]
@@ -120,7 +136,7 @@ mod tests {
#[test]
fn defaults() {
- let SP1Context { hook_registry, subproof_verifier, max_cycles: cycle_limit } =
+ let SP1Context { hook_registry, subproof_verifier, max_cycles: cycle_limit, .. } =
SP1Context::builder().build();
assert!(hook_registry.is_none());
assert!(subproof_verifier.is_none());
diff --git a/crates/core/executor/src/events/alu.rs b/crates/core/executor/src/events/alu.rs
index 2d2b14fe03..a42ce9ee82 100644
--- a/crates/core/executor/src/events/alu.rs
+++ b/crates/core/executor/src/events/alu.rs
@@ -9,6 +9,7 @@ use super::{create_random_lookup_ids, LookupId};
/// This object encapsulated the information needed to prove an ALU operation. This includes its
/// shard, opcode, operands, and other relevant information.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[repr(C)]
pub struct AluEvent {
/// The lookup identifier.
pub lookup_id: LookupId,
diff --git a/crates/core/executor/src/events/memory.rs b/crates/core/executor/src/events/memory.rs
index 655e0fc21d..d0e07109fb 100644
--- a/crates/core/executor/src/events/memory.rs
+++ b/crates/core/executor/src/events/memory.rs
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
/// This object encapsulates the information needed to prove a memory access operation. This
/// includes the shard, timestamp, and value of the memory address.
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
+#[repr(C)]
pub struct MemoryRecord {
/// The shard number.
pub shard: u32,
@@ -39,6 +40,7 @@ pub enum MemoryAccessPosition {
/// includes the value, shard, timestamp, and previous shard and timestamp.
#[allow(clippy::manual_non_exhaustive)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
+#[repr(C)]
pub struct MemoryReadRecord {
/// The value.
pub value: u32,
@@ -58,6 +60,7 @@ pub struct MemoryReadRecord {
/// includes the value, shard, timestamp, previous value, previous shard, and previous timestamp.
#[allow(clippy::manual_non_exhaustive)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
+#[repr(C)]
pub struct MemoryWriteRecord {
/// The value.
pub value: u32,
@@ -126,7 +129,8 @@ impl MemoryRecordEnum {
/// This object encapsulates the information needed to prove a memory initialize or finalize
/// operation. This includes the address, value, shard, timestamp, and whether the memory is
/// initialized or finalized.
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[repr(C)]
pub struct MemoryInitializeFinalizeEvent {
/// The address.
pub addr: u32,
@@ -223,7 +227,8 @@ impl From for MemoryRecordEnum {
/// This object encapsulates the information needed to prove a memory access operation within a
/// shard. This includes the address, initial memory access, and final memory access within a
/// shard.
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[repr(C)]
pub struct MemoryLocalEvent {
/// The address.
pub addr: u32,
diff --git a/crates/core/executor/src/events/precompiles/mod.rs b/crates/core/executor/src/events/precompiles/mod.rs
index d55a2093b2..29e62fd17c 100644
--- a/crates/core/executor/src/events/precompiles/mod.rs
+++ b/crates/core/executor/src/events/precompiles/mod.rs
@@ -4,8 +4,10 @@ mod fptower;
mod keccak256_permute;
mod sha256_compress;
mod sha256_extend;
+mod u256x2048_mul;
mod uint256;
+use crate::syscalls::SyscallCode;
pub use ec::*;
pub use edwards::*;
pub use fptower::*;
@@ -15,10 +17,9 @@ use serde::{Deserialize, Serialize};
pub use sha256_compress::*;
pub use sha256_extend::*;
use strum::{EnumIter, IntoEnumIterator};
+pub use u256x2048_mul::*;
pub use uint256::*;
-use crate::syscalls::SyscallCode;
-
use super::{MemoryLocalEvent, SyscallEvent};
#[derive(Clone, Debug, Serialize, Deserialize, EnumIter)]
@@ -72,6 +73,8 @@ pub enum PrecompileEvent {
Bls12381Fp2Mul(Fp2MulEvent),
/// Uint256 mul precompile event.
Uint256Mul(Uint256MulEvent),
+ /// U256XU2048 mul precompile event.
+ U256xU2048Mul(U256xU2048MulEvent),
}
/// Trait to retrieve all the local memory events from a vec of precompile events.
@@ -120,6 +123,9 @@ impl PrecompileLocalMemory for Vec<(SyscallEvent, PrecompileEvent)> {
PrecompileEvent::Uint256Mul(e) => {
iterators.push(e.local_mem_access.iter());
}
+ PrecompileEvent::U256xU2048Mul(e) => {
+ iterators.push(e.local_mem_access.iter());
+ }
PrecompileEvent::Bls12381Fp(e) | PrecompileEvent::Bn254Fp(e) => {
iterators.push(e.local_mem_access.iter());
}
@@ -166,7 +172,7 @@ impl PrecompileEvents {
#[inline]
/// Add a precompile event for a given syscall code.
- pub(crate) fn add_event(
+ pub fn add_event(
&mut self,
syscall_code: SyscallCode,
syscall_event: SyscallEvent,
diff --git a/crates/core/executor/src/events/precompiles/u256x2048_mul.rs b/crates/core/executor/src/events/precompiles/u256x2048_mul.rs
new file mode 100644
index 0000000000..e44a45ce2f
--- /dev/null
+++ b/crates/core/executor/src/events/precompiles/u256x2048_mul.rs
@@ -0,0 +1,49 @@
+use serde::{Deserialize, Serialize};
+
+use crate::events::{
+ memory::{MemoryLocalEvent, MemoryReadRecord, MemoryWriteRecord},
+ LookupId,
+};
+
+/// `U256xU2048` Mul Event.
+///
+/// This event is emitted when a `U256xU2048` mul operation is performed.
+#[derive(Default, Debug, Clone, Serialize, Deserialize)]
+pub struct U256xU2048MulEvent {
+ /// The lookup identifier.
+ pub lookup_id: LookupId,
+ /// The shard number.
+ pub shard: u32,
+ /// The channel number.
+ pub clk: u32,
+ /// The pointer to the a value.
+ pub a_ptr: u32,
+ /// The a value as a list of words.
+ pub a: Vec,
+ /// The pointer to the b value.
+ pub b_ptr: u32,
+ /// The b value as a list of words.
+ pub b: Vec,
+ /// The pointer to the lo value.
+ pub lo_ptr: u32,
+ /// The memory record for the pointer to the lo value.
+ pub lo_ptr_memory: MemoryReadRecord,
+ /// The lo value as a list of words.
+ pub lo: Vec,
+ /// The pointer to the hi value.
+ pub hi_ptr: u32,
+ /// The memory record for the pointer to the hi value.
+ pub hi_ptr_memory: MemoryReadRecord,
+ /// The hi value as a list of words.
+ pub hi: Vec,
+ /// The memory records for the a value.
+ pub a_memory_records: Vec,
+ /// The memory records for the b value.
+ pub b_memory_records: Vec,
+ /// The memory records for lo.
+ pub lo_memory_records: Vec,
+ /// The memory records for hi.
+ pub hi_memory_records: Vec,
+ /// The local memory access events.
+ pub local_mem_access: Vec,
+}
diff --git a/crates/core/executor/src/events/syscall.rs b/crates/core/executor/src/events/syscall.rs
index 23f9263ba8..09227c5a50 100644
--- a/crates/core/executor/src/events/syscall.rs
+++ b/crates/core/executor/src/events/syscall.rs
@@ -4,9 +4,10 @@ use super::LookupId;
/// Syscall Event.
///
-/// This object encapsulated the information needed to prove a syscall invocation from the CPU table.
-/// This includes its shard, clk, syscall id, arguments, other relevant information.
+/// This object encapsulated the information needed to prove a syscall invocation from the CPU
+/// table. This includes its shard, clk, syscall id, arguments, other relevant information.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[repr(C)]
pub struct SyscallEvent {
/// The shard number.
pub shard: u32,
diff --git a/crates/core/executor/src/events/utils.rs b/crates/core/executor/src/events/utils.rs
index d4b38df745..2c70f67c8d 100644
--- a/crates/core/executor/src/events/utils.rs
+++ b/crates/core/executor/src/events/utils.rs
@@ -1,13 +1,9 @@
-use serde::Deserialize;
-use serde::Serialize;
-use std::{
- fmt::Display,
- iter::{Map, Peekable},
-};
+use serde::{Deserialize, Serialize};
+use std::fmt::Display;
/// A unique identifier for lookups.
#[derive(Deserialize, Serialize, Debug, Clone, Copy, Default, Eq, Hash, PartialEq)]
-
+#[repr(C)]
pub struct LookupId(pub u64);
/// Create a random lookup id. This is slower than `record.create_lookup_id()` but is useful for
@@ -17,32 +13,64 @@ pub(crate) fn create_random_lookup_ids() -> [LookupId; 6] {
std::array::from_fn(|_| LookupId(rand::random()))
}
-/// Returns sorted and formatted rows of a table of counts (e.g. `opcode_counts`).
+/// Returns a tuple containing everything needed to to correctly display a table of counts
+/// (e.g. `opcode_counts`):
///
-/// The table is sorted first by count (descending) and then by label (ascending).
-/// The first column consists of the counts, is right-justified, and is padded precisely
-/// enough to fit all the numbers. The second column consists of the labels (e.g. `OpCode`s).
-/// The columns are separated by a single space character.
-#[allow(clippy::type_complexity)]
+/// 1. The number of characters of the highest count, that can be used to right-justify the count
+/// column.
+///
+/// 2. The table sorted first by count (descending) and then by label (ascending). The table
+/// itself is an iterator of a tuple (label, count).
pub fn sorted_table_lines<'a, K, V>(
- table: impl IntoIterator- + 'a,
-) -> Map<
- Peekable
, impl FnMut((K, V)) -> (String, String)>>,
- impl FnMut((String, String)) -> String,
->
+ table: impl IntoIterator- + 'a,
+) -> (usize, impl Iterator
- )
where
K: Ord + Display + 'a,
V: Ord + Display + 'a,
{
let mut entries = table.into_iter().collect::
>();
// Sort table by count (descending), then the name order (ascending).
- entries.sort_unstable_by(|a, b| a.1.cmp(&b.1).reverse().then_with(|| a.0.cmp(&b.0)));
+ entries.sort_unstable_by(|a, b| a.1.cmp(b.1).reverse().then_with(|| a.0.cmp(&b.0)));
// Convert counts to `String`s to prepare them for printing and to measure their width.
- let mut table_with_string_counts = entries
- .into_iter()
- .map(|(label, ct)| (label.to_string().to_lowercase(), ct.to_string()))
- .peekable();
+ let mut entries =
+ entries.into_iter().map(|(label, ct)| (label.to_string().to_lowercase(), ct)).peekable();
// Calculate width for padding the counts.
- let width = table_with_string_counts.peek().map(|(_, b)| b.len()).unwrap_or_default();
- table_with_string_counts.map(move |(label, count)| format!("{count:>width$} {label}"))
+ let width = entries.peek().map(|(_, b)| b.to_string().len()).unwrap_or_default();
+
+ (width, entries)
+}
+
+/// Returns a formatted row of a table of counts (e.g. `opcode_counts`).
+///
+/// The first column consists of the counts, is right-justified, and is padded precisely
+/// enough to fit all the numbers, using the provided `width`. The second column consists of
+/// the labels (e.g. `OpCode`s). The columns are separated by a single space character.
+#[must_use]
+pub fn format_table_line(width: &usize, label: &str, count: &V) -> String
+where
+ V: Display,
+{
+ format!("{count:>width$} {label}")
+}
+
+/// Returns sorted and formatted rows of a table of counts (e.g. `opcode_counts`).
+///
+/// The table is sorted first by count (descending) and then by label (ascending).
+/// The first column consists of the counts, is right-justified, and is padded precisely
+/// enough to fit all the numbers. The second column consists of the labels (e.g. `OpCode`s).
+/// The columns are separated by a single space character.
+///
+/// It's possible to hide rows with 0 count by setting `hide_zeros` to true.
+pub fn generate_execution_report<'a, K, V>(
+ table: impl IntoIterator- + 'a,
+) -> impl Iterator
- + 'a
+where
+ K: Ord + Display + 'a,
+ V: Ord + PartialEq
+ Display + 'a,
+{
+ let (width, lines) = sorted_table_lines(table);
+
+ lines
+ .filter(move |(_, count)| **count != 0)
+ .map(move |(label, count)| format!(" {}", format_table_line(&width, &label, count)))
}
diff --git a/crates/core/executor/src/executor.rs b/crates/core/executor/src/executor.rs
index e80d894bbe..c2cc1915ab 100644
--- a/crates/core/executor/src/executor.rs
+++ b/crates/core/executor/src/executor.rs
@@ -6,7 +6,7 @@ use std::{
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
-use sp1_stark::SP1CoreOpts;
+use sp1_stark::{air::PublicValues, SP1CoreOpts};
use thiserror::Error;
use crate::{
@@ -26,6 +26,15 @@ use crate::{
Instruction, Opcode, Program, Register,
};
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+/// Whether to verify deferred proofs during execution.
+pub enum DeferredProofVerification {
+ /// Verify deferred proofs during execution.
+ Enabled,
+ /// Skip verification of deferred proofs
+ Disabled,
+}
+
/// An executor for the SP1 RISC-V zkVM.
///
/// The exeuctor is responsible for executing a user program and tracing important events which
@@ -70,8 +79,9 @@ pub struct Executor<'a> {
/// checkpoints.
pub memory_checkpoint: PagedMemory>,
- /// Memory addresses that were initialized in this batch of shards. Used to minimize the size of
- /// checkpoints. The value stored is whether or not it had a value at the beginning of the batch.
+ /// Memory addresses that were initialized in this batch of shards. Used to minimize the size
+ /// of checkpoints. The value stored is whether or not it had a value at the beginning of
+ /// the batch.
pub uninitialized_memory_checkpoint: PagedMemory,
/// The memory accesses for the current cycle.
@@ -80,6 +90,9 @@ pub struct Executor<'a> {
/// The maximum number of cpu cycles to use for execution.
pub max_cycles: Option,
+ /// Skip deferred proof verification.
+ pub deferred_proof_verification: DeferredProofVerification,
+
/// The state of the execution.
pub state: ExecutionState,
@@ -231,6 +244,11 @@ impl<'a> Executor<'a> {
hook_registry,
opts,
max_cycles: context.max_cycles,
+ deferred_proof_verification: if context.skip_deferred_proof_verification {
+ DeferredProofVerification::Disabled
+ } else {
+ DeferredProofVerification::Enabled
+ },
memory_checkpoint: PagedMemory::new_preallocated(),
uninitialized_memory_checkpoint: PagedMemory::new_preallocated(),
local_memory_access: HashMap::new(),
@@ -1373,7 +1391,7 @@ impl<'a> Executor<'a> {
pub fn execute_state(
&mut self,
emit_global_memory_events: bool,
- ) -> Result<(ExecutionState, bool), ExecutionError> {
+ ) -> Result<(ExecutionState, PublicValues, bool), ExecutionError> {
self.memory_checkpoint.clear();
self.executor_mode = ExecutorMode::Checkpoint;
self.emit_global_memory_events = emit_global_memory_events;
@@ -1388,6 +1406,7 @@ impl<'a> Executor<'a> {
let done = tracing::debug_span!("execute").in_scope(|| self.execute())?;
// Create a checkpoint using `memory_checkpoint`. Just include all memory if `done` since we
// need it all for MemoryFinalize.
+ let next_pc = self.state.pc;
tracing::debug_span!("create memory checkpoint").in_scope(|| {
let memory_checkpoint = std::mem::take(&mut self.memory_checkpoint);
let uninitialized_memory_checkpoint =
@@ -1423,10 +1442,14 @@ impl<'a> Executor<'a> {
.collect();
}
});
+ let mut public_values = self.records.last().as_ref().unwrap().public_values;
+ public_values.start_pc = next_pc;
+ public_values.next_pc = next_pc;
+ println!("public values: {public_values:?}");
if !done {
self.records.clear();
}
- Ok((checkpoint, done))
+ Ok((checkpoint, public_values, done))
}
fn initialize(&mut self) {
@@ -1670,7 +1693,7 @@ mod tests {
use crate::programs::tests::{
fibonacci_program, panic_program, secp256r1_add_program, secp256r1_double_program,
- simple_memory_program, simple_program, ssz_withdrawals_program,
+ simple_memory_program, simple_program, ssz_withdrawals_program, u256xu2048_mul_program,
};
use crate::Register;
@@ -1713,6 +1736,13 @@ mod tests {
runtime.run().unwrap();
}
+ #[test]
+ fn test_u256xu2048_mul() {
+ let program = u256xu2048_mul_program();
+ let mut runtime = Executor::new(program, SP1CoreOpts::default());
+ runtime.run().unwrap();
+ }
+
#[test]
fn test_ssz_withdrawals_program_run() {
let program = ssz_withdrawals_program();
diff --git a/crates/core/executor/src/hook.rs b/crates/core/executor/src/hook.rs
index e5479f623f..c15e803e45 100644
--- a/crates/core/executor/src/hook.rs
+++ b/crates/core/executor/src/hook.rs
@@ -3,8 +3,10 @@ use core::fmt::Debug;
use std::sync::{Arc, RwLock, RwLockWriteGuard};
use hashbrown::HashMap;
-use sp1_curves::k256::{Invert, RecoveryId, Signature, VerifyingKey};
-use sp1_curves::p256::Signature as p256Signature;
+use sp1_curves::{
+ k256::{Invert, RecoveryId, Signature, VerifyingKey},
+ p256::Signature as p256Signature,
+};
use crate::Executor;
diff --git a/crates/core/executor/src/instruction.rs b/crates/core/executor/src/instruction.rs
index 10dfa5476d..cbea85daaf 100644
--- a/crates/core/executor/src/instruction.rs
+++ b/crates/core/executor/src/instruction.rs
@@ -11,6 +11,7 @@ use crate::opcode::Opcode;
/// as 32-bit words, but instead use a custom encoding that is more friendly to decode in the
/// SP1 zkVM.
#[derive(Clone, Copy, Serialize, Deserialize)]
+#[repr(C)]
pub struct Instruction {
/// The operation to execute.
pub opcode: Opcode,
diff --git a/crates/core/executor/src/memory.rs b/crates/core/executor/src/memory.rs
index a036bbf5ca..bdaf468a6f 100644
--- a/crates/core/executor/src/memory.rs
+++ b/crates/core/executor/src/memory.rs
@@ -198,7 +198,8 @@ impl<'a, V: Copy> Entry<'a, V> {
}
}
- /// Provides in-place mutable access to an occupied entry before any potential inserts into the map.
+ /// Provides in-place mutable access to an occupied entry before any potential inserts into the
+ /// map.
pub fn and_modify(mut self, f: F) -> Self {
match &mut self {
Entry::Vacant(_) => {}
diff --git a/crates/core/executor/src/opcode.rs b/crates/core/executor/src/opcode.rs
index 818b5b1f2b..b8dd250e95 100644
--- a/crates/core/executor/src/opcode.rs
+++ b/crates/core/executor/src/opcode.rs
@@ -24,6 +24,7 @@ use serde::{Deserialize, Serialize};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Enum,
)]
+#[repr(u8)]
pub enum Opcode {
/// rd ← rs1 + rs2, pc ← pc + 4
ADD = 0,
diff --git a/crates/core/executor/src/program.rs b/crates/core/executor/src/program.rs
index 09bb70cac4..8dcf4ef715 100644
--- a/crates/core/executor/src/program.rs
+++ b/crates/core/executor/src/program.rs
@@ -2,17 +2,23 @@
use std::{fs::File, io::Read};
-use hashbrown::HashMap;
-use p3_field::Field;
-use serde::{Deserialize, Serialize};
-use sp1_stark::air::{MachineAir, MachineProgram};
-
use crate::{
disassembler::{transpile, Elf},
instruction::Instruction,
CoreShape,
};
-
+use hashbrown::HashMap;
+use p3_field::AbstractExtensionField;
+use p3_field::Field;
+use p3_field::PrimeField;
+use p3_maybe_rayon::prelude::IntoParallelIterator;
+use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator};
+use serde::{Deserialize, Serialize};
+use sp1_stark::air::{MachineAir, MachineProgram};
+use sp1_stark::septic_curve::{SepticCurve, SepticCurveComplete};
+use sp1_stark::septic_digest::SepticDigest;
+use sp1_stark::septic_extension::SepticExtension;
+use sp1_stark::InteractionKind;
/// A program that can be executed by the SP1 zkVM.
///
/// Contains a series of instructions along with the initial memory image. It also contains the
@@ -98,8 +104,35 @@ impl Program {
}
}
-impl MachineProgram for Program {
+impl MachineProgram for Program {
fn pc_start(&self) -> F {
F::from_canonical_u32(self.pc_start)
}
+
+ fn initial_global_cumulative_sum(&self) -> SepticDigest {
+ let mut digests: Vec> = self
+ .memory_image
+ .iter()
+ .par_bridge()
+ .map(|(&addr, &word)| {
+ let values = [
+ (InteractionKind::Memory as u32) << 24,
+ 0,
+ addr,
+ word & 255,
+ (word >> 8) & 255,
+ (word >> 16) & 255,
+ (word >> 24) & 255,
+ ];
+ let x_start =
+ SepticExtension::::from_base_fn(|i| F::from_canonical_u32(values[i]));
+ let (point, _) = SepticCurve::::lift_x(x_start);
+ SepticCurveComplete::Affine(point.neg())
+ })
+ .collect();
+ digests.push(SepticCurveComplete::Affine(SepticDigest::::zero().0));
+ SepticDigest(
+ digests.into_par_iter().reduce(|| SepticCurveComplete::Infinity, |a, b| a + b).point(),
+ )
+ }
}
diff --git a/crates/core/executor/src/programs.rs b/crates/core/executor/src/programs.rs
index 3212e32d4e..d281c27875 100644
--- a/crates/core/executor/src/programs.rs
+++ b/crates/core/executor/src/programs.rs
@@ -5,126 +5,10 @@
pub mod tests {
use crate::{Instruction, Opcode, Program};
- pub const CHESS_ELF: &[u8] =
- include_bytes!("../../../../examples/chess/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const FIBONACCI_IO_ELF: &[u8] =
- include_bytes!("../../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const IO_ELF: &[u8] =
- include_bytes!("../../../../examples/io/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const JSON_ELF: &[u8] =
- include_bytes!("../../../../examples/json/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const REGEX_ELF: &[u8] =
- include_bytes!("../../../../examples/regex/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const RSA_ELF: &[u8] =
- include_bytes!("../../../../examples/rsa/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SSZ_WITHDRAWALS_ELF: &[u8] = include_bytes!(
- "../../../../examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf"
- );
-
- pub const TENDERMINT_ELF: &[u8] =
- include_bytes!("../../../../examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf");
-
- pub const FIBONACCI_ELF: &[u8] =
- include_bytes!("../../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf");
-
- pub const ED25519_ELF: &[u8] =
- include_bytes!("../../../../tests/ed25519/elf/riscv32im-succinct-zkvm-elf");
-
- pub const CYCLE_TRACKER_ELF: &[u8] =
- include_bytes!("../../../../tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf");
-
- pub const ED_ADD_ELF: &[u8] =
- include_bytes!("../../../../tests/ed-add/elf/riscv32im-succinct-zkvm-elf");
-
- pub const ED_DECOMPRESS_ELF: &[u8] =
- include_bytes!("../../../../tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf");
-
- pub const KECCAK_PERMUTE_ELF: &[u8] =
- include_bytes!("../../../../tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf");
-
- pub const KECCAK256_ELF: &[u8] =
- include_bytes!("../../../../tests/keccak256/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256K1_ADD_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256K1_DECOMPRESS_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256K1_DOUBLE_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256R1_ADD_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256R1_DOUBLE_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SHA_COMPRESS_ELF: &[u8] =
- include_bytes!("../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SHA_EXTEND_ELF: &[u8] =
- include_bytes!("../../../../tests/sha-extend/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SHA2_ELF: &[u8] =
- include_bytes!("../../../../tests/sha2/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_ADD_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-add/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_DOUBLE_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-double/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf");
-
- pub const SECP256K1_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_ADD_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_DOUBLE_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf");
-
- pub const UINT256_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_DECOMPRESS_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf");
-
- pub const VERIFY_PROOF_ELF: &[u8] =
- include_bytes!("../../../../tests/verify-proof/elf/riscv32im-succinct-zkvm-elf");
-
- pub const PANIC_ELF: &[u8] =
- include_bytes!("../../../../tests/panic/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_FP_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_FP2_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BLS12381_FP2_ADDSUB_ELF: &[u8] =
- include_bytes!("../../../../tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_FP_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_FP2_ADDSUB_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf");
-
- pub const BN254_FP2_MUL_ELF: &[u8] =
- include_bytes!("../../../../tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf");
+ use test_artifacts::{
+ FIBONACCI_ELF, KECCAK_PERMUTE_ELF, PANIC_ELF, SECP256R1_ADD_ELF, SECP256R1_DOUBLE_ELF,
+ U256XU2048_MUL_ELF,
+ };
#[must_use]
pub fn simple_program() -> Program {
@@ -166,6 +50,16 @@ pub mod tests {
Program::from(SECP256R1_DOUBLE_ELF).unwrap()
}
+ /// Get the u256x2048 mul program.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the program fails to load.
+ #[must_use]
+ pub fn u256xu2048_mul_program() -> Program {
+ Program::from(U256XU2048_MUL_ELF).unwrap()
+ }
+
/// Get the SSZ withdrawals program.
///
/// # Panics
diff --git a/crates/core/executor/src/record.rs b/crates/core/executor/src/record.rs
index f9e89acb4c..fbf79cf01a 100644
--- a/crates/core/executor/src/record.rs
+++ b/crates/core/executor/src/record.rs
@@ -178,7 +178,15 @@ impl ExecutionRecord {
/// Splits the deferred [`ExecutionRecord`] into multiple [`ExecutionRecord`]s, each which
/// contain a "reasonable" number of deferred events.
- pub fn split(&mut self, last: bool, opts: SplitOpts) -> Vec {
+ ///
+ /// The optional `last_record` will be provided if there are few enough deferred events that
+ /// they can all be packed into the already existing last record.
+ pub fn split(
+ &mut self,
+ last: bool,
+ last_record: Option<&mut ExecutionRecord>,
+ opts: SplitOpts,
+ ) -> Vec {
let mut shards = Vec::new();
let precompile_events = take(&mut self.precompile_events);
@@ -216,6 +224,18 @@ impl ExecutionRecord {
self.global_memory_initialize_events.sort_by_key(|event| event.addr);
self.global_memory_finalize_events.sort_by_key(|event| event.addr);
+ // If there are no precompile shards, and `last_record` is Some, pack the memory events
+ // into the last record.
+ let pack_memory_events_into_last_record = last_record.is_some() && shards.is_empty();
+ let mut blank_record = ExecutionRecord::new(self.program.clone());
+
+ // If `last_record` is None, use a blank record to store the memory events.
+ let last_record_ref = if pack_memory_events_into_last_record {
+ last_record.unwrap()
+ } else {
+ &mut blank_record
+ };
+
let mut init_addr_bits = [0; 32];
let mut finalize_addr_bits = [0; 32];
for mem_chunks in self
@@ -230,28 +250,34 @@ impl ExecutionRecord {
EitherOrBoth::Left(mem_init_chunk) => (mem_init_chunk, [].as_slice()),
EitherOrBoth::Right(mem_finalize_chunk) => ([].as_slice(), mem_finalize_chunk),
};
- let mut shard = ExecutionRecord::new(self.program.clone());
- shard.global_memory_initialize_events.extend_from_slice(mem_init_chunk);
- shard.public_values.previous_init_addr_bits = init_addr_bits;
+ last_record_ref.global_memory_initialize_events.extend_from_slice(mem_init_chunk);
+ last_record_ref.public_values.previous_init_addr_bits = init_addr_bits;
if let Some(last_event) = mem_init_chunk.last() {
let last_init_addr_bits = core::array::from_fn(|i| (last_event.addr >> i) & 1);
init_addr_bits = last_init_addr_bits;
}
- shard.public_values.last_init_addr_bits = init_addr_bits;
+ last_record_ref.public_values.last_init_addr_bits = init_addr_bits;
- shard.global_memory_finalize_events.extend_from_slice(mem_finalize_chunk);
- shard.public_values.previous_finalize_addr_bits = finalize_addr_bits;
+ last_record_ref.global_memory_finalize_events.extend_from_slice(mem_finalize_chunk);
+ last_record_ref.public_values.previous_finalize_addr_bits = finalize_addr_bits;
if let Some(last_event) = mem_finalize_chunk.last() {
let last_finalize_addr_bits =
core::array::from_fn(|i| (last_event.addr >> i) & 1);
finalize_addr_bits = last_finalize_addr_bits;
}
- shard.public_values.last_finalize_addr_bits = finalize_addr_bits;
+ last_record_ref.public_values.last_finalize_addr_bits = finalize_addr_bits;
+
+ if !pack_memory_events_into_last_record {
+ // If not packing memory events into the last record, add 'last_record_ref'
+ // to the returned records. `take` replaces `blank_program` with the default.
+ shards.push(take(last_record_ref));
- shards.push(shard);
+ // Reset the last record so its program is the correct one. (The default program
+ // provided by `take` contains no instructions.)
+ last_record_ref.program = self.program.clone();
+ }
}
}
-
shards
}
diff --git a/crates/core/executor/src/report.rs b/crates/core/executor/src/report.rs
index 6f15579216..00fe56ab23 100644
--- a/crates/core/executor/src/report.rs
+++ b/crates/core/executor/src/report.rs
@@ -6,7 +6,7 @@ use std::{
use enum_map::{EnumArray, EnumMap};
use hashbrown::HashMap;
-use crate::{events::sorted_table_lines, syscalls::SyscallCode, Opcode};
+use crate::{events::generate_execution_report, syscalls::SyscallCode, Opcode};
/// An execution report.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -68,12 +68,12 @@ impl Add for ExecutionReport {
impl Display for ExecutionReport {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
writeln!(f, "opcode counts ({} total instructions):", self.total_instruction_count())?;
- for line in sorted_table_lines(self.opcode_counts.as_ref()) {
+ for line in generate_execution_report(self.opcode_counts.as_ref()) {
writeln!(f, " {line}")?;
}
writeln!(f, "syscall counts ({} total syscall instructions):", self.total_syscall_count())?;
- for line in sorted_table_lines(self.syscall_counts.as_ref()) {
+ for line in generate_execution_report(self.syscall_counts.as_ref()) {
writeln!(f, " {line}")?;
}
diff --git a/crates/core/executor/src/state.rs b/crates/core/executor/src/state.rs
index 4c669188df..55ba22e321 100644
--- a/crates/core/executor/src/state.rs
+++ b/crates/core/executor/src/state.rs
@@ -29,7 +29,8 @@ pub struct ExecutionState {
/// + timestamp that each memory address was accessed.
pub memory: PagedMemory,
- /// The global clock keeps track of how many instructions have been executed through all shards.
+ /// The global clock keeps track of how many instructions have been executed through all
+ /// shards.
pub global_clk: u64,
/// The clock increments by 4 (possibly more in syscalls) for each instruction that has been
diff --git a/crates/core/executor/src/syscalls/code.rs b/crates/core/executor/src/syscalls/code.rs
index 1891a3f742..59fe5c7de8 100644
--- a/crates/core/executor/src/syscalls/code.rs
+++ b/crates/core/executor/src/syscalls/code.rs
@@ -23,6 +23,7 @@ use strum_macros::EnumIter;
)]
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
+#[repr(u32)]
pub enum SyscallCode {
/// Halts the program.
HALT = 0x00_00_00_00,
@@ -87,6 +88,9 @@ pub enum SyscallCode {
/// Executes the `UINT256_MUL` precompile.
UINT256_MUL = 0x00_01_01_1D,
+ /// Executes the `U256XU2048_MUL` precompile.
+ U256XU2048_MUL = 0x00_01_01_2F,
+
/// Executes the `BLS12381_ADD` precompile.
BLS12381_ADD = 0x00_01_01_1E,
@@ -166,6 +170,7 @@ impl SyscallCode {
0x00_00_00_F0 => SyscallCode::HINT_LEN,
0x00_00_00_F1 => SyscallCode::HINT_READ,
0x00_01_01_1D => SyscallCode::UINT256_MUL,
+ 0x00_01_01_2F => SyscallCode::U256XU2048_MUL,
0x00_01_01_20 => SyscallCode::BLS12381_FP_ADD,
0x00_01_01_21 => SyscallCode::BLS12381_FP_SUB,
0x00_01_01_22 => SyscallCode::BLS12381_FP_MUL,
diff --git a/crates/core/executor/src/syscalls/context.rs b/crates/core/executor/src/syscalls/context.rs
index 74dfafb279..64f41dc7ab 100644
--- a/crates/core/executor/src/syscalls/context.rs
+++ b/crates/core/executor/src/syscalls/context.rs
@@ -110,9 +110,9 @@ impl<'a, 'b> SyscallContext<'a, 'b> {
let mut syscall_local_mem_events = Vec::new();
if !self.rt.unconstrained && self.rt.executor_mode == ExecutorMode::Trace {
- // Will need to transfer the existing memory local events in the executor to it's record,
- // and return all the syscall memory local events. This is similar to what
- // `bump_record` does.
+ // Will need to transfer the existing memory local events in the executor to it's
+ // record, and return all the syscall memory local events. This is similar
+ // to what `bump_record` does.
for (addr, event) in self.local_memory_access.drain() {
let local_mem_access = self.rt.local_memory_access.remove(&addr);
diff --git a/crates/core/executor/src/syscalls/mod.rs b/crates/core/executor/src/syscalls/mod.rs
index 43811050b3..8abb75bc2e 100644
--- a/crates/core/executor/src/syscalls/mod.rs
+++ b/crates/core/executor/src/syscalls/mod.rs
@@ -26,6 +26,7 @@ use precompiles::{
fptower::{Fp2AddSubSyscall, Fp2MulSyscall, FpOpSyscall},
keccak256::permute::Keccak256PermuteSyscall,
sha256::{compress::Sha256CompressSyscall, extend::Sha256ExtendSyscall},
+ u256x2048_mul::U256xU2048MulSyscall,
uint256::Uint256MulSyscall,
weierstrass::{
add::WeierstrassAddAssignSyscall, decompress::WeierstrassDecompressSyscall,
@@ -145,6 +146,8 @@ pub fn default_syscall_map() -> HashMap> {
syscall_map.insert(SyscallCode::UINT256_MUL, Arc::new(Uint256MulSyscall));
+ syscall_map.insert(SyscallCode::U256XU2048_MUL, Arc::new(U256xU2048MulSyscall));
+
syscall_map.insert(
SyscallCode::BLS12381_FP_ADD,
Arc::new(FpOpSyscall::::new(FieldOperation::Add)),
diff --git a/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs
index f583432310..b433f6384a 100644
--- a/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs
+++ b/crates/core/executor/src/syscalls/precompiles/fptower/fp2_addsub.rs
@@ -86,8 +86,8 @@ impl Syscall for Fp2AddSubSyscall {
local_mem_access: rt.postprocess(),
};
match P::FIELD_TYPE {
- // All the fp2 add and sub events for a given curve are coalesced to the curve's fp2 add operation. Only check for
- // that operation.
+ // All the fp2 add and sub events for a given curve are coalesced to the curve's fp2 add
+ // operation. Only check for that operation.
// TODO: Fix this.
FieldType::Bn254 => {
let syscall_code_key = match syscall_code {
diff --git a/crates/core/executor/src/syscalls/precompiles/mod.rs b/crates/core/executor/src/syscalls/precompiles/mod.rs
index f07da94609..4b06dd3c12 100644
--- a/crates/core/executor/src/syscalls/precompiles/mod.rs
+++ b/crates/core/executor/src/syscalls/precompiles/mod.rs
@@ -2,5 +2,6 @@ pub mod edwards;
pub mod fptower;
pub mod keccak256;
pub mod sha256;
+pub mod u256x2048_mul;
pub mod uint256;
pub mod weierstrass;
diff --git a/crates/core/executor/src/syscalls/precompiles/u256x2048_mul.rs b/crates/core/executor/src/syscalls/precompiles/u256x2048_mul.rs
new file mode 100644
index 0000000000..3795055608
--- /dev/null
+++ b/crates/core/executor/src/syscalls/precompiles/u256x2048_mul.rs
@@ -0,0 +1,91 @@
+use num::{BigUint, Integer, One};
+
+use sp1_primitives::consts::{bytes_to_words_le, words_to_bytes_le_vec};
+
+use crate::{
+ events::{PrecompileEvent, U256xU2048MulEvent},
+ syscalls::{Syscall, SyscallCode, SyscallContext},
+ Register::{X12, X13},
+};
+
+const U256_NUM_WORDS: usize = 8;
+const U2048_NUM_WORDS: usize = 64;
+const U256_NUM_BYTES: usize = U256_NUM_WORDS * 4;
+const U2048_NUM_BYTES: usize = U2048_NUM_WORDS * 4;
+
+pub(crate) struct U256xU2048MulSyscall;
+
+impl Syscall for U256xU2048MulSyscall {
+ fn execute(
+ &self,
+ rt: &mut SyscallContext,
+ syscall_code: SyscallCode,
+ arg1: u32,
+ arg2: u32,
+ ) -> Option {
+ let clk = rt.clk;
+
+ let a_ptr = arg1;
+ let b_ptr = arg2;
+
+ let (lo_ptr_memory, lo_ptr) = rt.mr(X12 as u32);
+ let (hi_ptr_memory, hi_ptr) = rt.mr(X13 as u32);
+
+ let (a_memory_records, a) = rt.mr_slice(a_ptr, U256_NUM_WORDS);
+ let (b_memory_records, b) = rt.mr_slice(b_ptr, U2048_NUM_WORDS);
+ let uint256_a = BigUint::from_bytes_le(&words_to_bytes_le_vec(&a));
+ let uint2048_b = BigUint::from_bytes_le(&words_to_bytes_le_vec(&b));
+
+ let result = uint256_a * uint2048_b;
+
+ let two_to_2048 = BigUint::one() << 2048;
+
+ let (hi, lo) = result.div_rem(&two_to_2048);
+
+ let mut lo_bytes = lo.to_bytes_le();
+ lo_bytes.resize(U2048_NUM_BYTES, 0u8);
+ let lo_words = bytes_to_words_le::(&lo_bytes);
+
+ let mut hi_bytes = hi.to_bytes_le();
+ hi_bytes.resize(U256_NUM_BYTES, 0u8);
+ let hi_words = bytes_to_words_le::(&hi_bytes);
+
+ // Increment clk so that the write is not at the same cycle as the read.
+ rt.clk += 1;
+
+ let lo_memory_records = rt.mw_slice(lo_ptr, &lo_words);
+ let hi_memory_records = rt.mw_slice(hi_ptr, &hi_words);
+ let lookup_id = rt.syscall_lookup_id;
+ let shard = rt.current_shard();
+ let event = PrecompileEvent::U256xU2048Mul(U256xU2048MulEvent {
+ lookup_id,
+ shard,
+ clk,
+ a_ptr,
+ a,
+ b_ptr,
+ b,
+ lo_ptr,
+ lo: lo_words.to_vec(),
+ hi_ptr,
+ hi: hi_words.to_vec(),
+ lo_ptr_memory,
+ hi_ptr_memory,
+ a_memory_records,
+ b_memory_records,
+ lo_memory_records,
+ hi_memory_records,
+ local_mem_access: rt.postprocess(),
+ });
+
+ let sycall_event =
+ rt.rt.syscall_event(clk, syscall_code.syscall_id(), arg1, arg2, lookup_id);
+ rt.add_precompile_event(syscall_code, sycall_event, event);
+
+ None
+ }
+
+ fn num_extra_cycles(&self) -> u32 {
+ 1
+ }
+}
diff --git a/crates/core/executor/src/syscalls/verify.rs b/crates/core/executor/src/syscalls/verify.rs
index 0197199e51..b17d795d3d 100644
--- a/crates/core/executor/src/syscalls/verify.rs
+++ b/crates/core/executor/src/syscalls/verify.rs
@@ -1,3 +1,5 @@
+use crate::DeferredProofVerification;
+
use super::{Syscall, SyscallCode, SyscallContext};
pub(crate) struct VerifySyscall;
@@ -32,16 +34,22 @@ impl Syscall for VerifySyscall {
let vkey_bytes: [u32; 8] = vkey.try_into().unwrap();
let pv_digest_bytes: [u32; 8] = pv_digest.try_into().unwrap();
- ctx.rt
- .subproof_verifier
- .verify_deferred_proof(proof, proof_vk, vkey_bytes, pv_digest_bytes)
- .unwrap_or_else(|e| {
- panic!(
- "Failed to verify proof {proof_index} with digest {}: {}",
- hex::encode(bytemuck::cast_slice(&pv_digest_bytes)),
- e
- )
- });
+ // Skip deferred proof verification if the corresponding runtime flag is set.
+ match ctx.rt.deferred_proof_verification {
+ DeferredProofVerification::Enabled => {
+ ctx.rt
+ .subproof_verifier
+ .verify_deferred_proof(proof, proof_vk, vkey_bytes, pv_digest_bytes)
+ .unwrap_or_else(|e| {
+ panic!(
+ "Failed to verify proof {proof_index} with digest {}: {}",
+ hex::encode(bytemuck::cast_slice(&pv_digest_bytes)),
+ e
+ )
+ });
+ }
+ DeferredProofVerification::Disabled => {}
+ }
None
}
diff --git a/crates/core/machine/Cargo.toml b/crates/core/machine/Cargo.toml
index 3bbd29d0b9..ff60ab4838 100644
--- a/crates/core/machine/Cargo.toml
+++ b/crates/core/machine/Cargo.toml
@@ -8,11 +8,12 @@ license = { workspace = true }
repository = { workspace = true }
keywords = { workspace = true }
categories = { workspace = true }
+links = "sp1-core-machine-sys"
[dependencies]
bincode = "1.3.3"
-serde = { version = "1.0", features = ["derive", "rc"] }
-itertools = "0.13.0"
+serde = { workspace = true, features = ["derive", "rc"] }
+itertools = { workspace = true }
log = "0.4.22"
num = { version = "0.4.3" }
p3-air = { workspace = true }
@@ -27,6 +28,9 @@ p3-util = { workspace = true }
sp1-derive = { workspace = true }
sp1-primitives = { workspace = true }
+rayon = "1.10.0"
+rayon-scan = "0.1.1"
+
amcl = { package = "snowbridge-amcl", version = "1.0.2", default-features = false, features = [
"bls381",
] }
@@ -41,15 +45,15 @@ p256 = { version = "0.13.2", features = ["expose-field"] }
num_cpus = "1.16.0"
size = "0.4.1"
tempfile = "3.10.1"
-tracing = "0.1.40"
+tracing = { workspace = true }
tracing-forest = { version = "0.1.6", features = ["ansi", "smallvec"] }
-tracing-subscriber = { version = "0.3.18", features = ["std", "env-filter"] }
+tracing-subscriber = { workspace = true, features = ["std", "env-filter"] }
strum_macros = "0.26"
strum = "0.26"
web-time = "1.1.0"
thiserror = "1.0.63"
rand = "0.8.5"
-hashbrown = { version = "0.14.5", features = ["serde", "inline-more"] }
+hashbrown = { workspace = true, features = ["serde", "inline-more"] }
static_assertions = "1.1.0"
sp1-stark = { workspace = true }
@@ -63,11 +67,23 @@ num = { version = "0.4.3", features = ["rand"] }
rand = "0.8.5"
sp1-zkvm = { workspace = true }
sp1-core-executor = { workspace = true, features = ["programs"] }
+test-artifacts = { workspace = true }
+
+[build-dependencies]
+sp1-stark = { workspace = true }
+sp1-primitives = { workspace = true }
+p3-baby-bear = { workspace = true }
+cbindgen = "0.27.0"
+cc = "1.1"
+pathdiff = "0.2.1"
+glob = "0.3.1"
[features]
+default = []
programs = []
debug = []
bigint-rug = ["sp1-curves/bigint-rug"]
+sys = []
[lib]
bench = false
diff --git a/crates/core/machine/build.rs b/crates/core/machine/build.rs
new file mode 100644
index 0000000000..f2088bd6ac
--- /dev/null
+++ b/crates/core/machine/build.rs
@@ -0,0 +1,169 @@
+fn main() {
+ #[cfg(feature = "sys")]
+ sys::build_ffi();
+}
+
+#[cfg(feature = "sys")]
+mod sys {
+ use std::{
+ env, fs, os,
+ path::{Path, PathBuf},
+ };
+
+ use pathdiff::diff_paths;
+
+ /// The library name, used for the static library archive and the headers.
+ /// Should be chosen as to not conflict with other library/header names.
+ const LIB_NAME: &str = "sp1-core-machine-sys";
+
+ /// The name of all include directories involved, used to find and output header files.
+ const INCLUDE_DIRNAME: &str = "include";
+
+ /// The name of the directory to recursively search for source files in.
+ const SOURCE_DIRNAME: &str = "cpp";
+
+ /// The warning placed in the cbindgen header.
+ const AUTOGEN_WARNING: &str =
+ "/* Automatically generated by `cbindgen`. Not intended for manual editing. */";
+
+ pub fn build_ffi() {
+ // The name of the header generated by `cbindgen`.
+ let cbindgen_hpp = &format!("{LIB_NAME}-cbindgen.hpp");
+
+ // The crate directory.
+ let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
+
+ // The output directory, where built artifacts should be placed.
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+
+ // The target directory that the cargo invocation is using.
+ // Headers are symlinked into `target/include` purely for IDE purposes.
+ let target_dir = {
+ let mut dir = out_dir.clone();
+ loop {
+ if dir.ends_with("target") {
+ break dir;
+ }
+ if !dir.pop() {
+ panic!("OUT_DIR does not have parent called \"target\": {:?}", out_dir);
+ }
+ }
+ };
+
+ // The directory to read headers from.
+ let source_include_dir = crate_dir.join(INCLUDE_DIRNAME);
+
+ // The directory to place headers into.
+ let target_include_dir = out_dir.join(INCLUDE_DIRNAME);
+
+ // The directory to place symlinks to headers into. Has the fixed path "target/include".
+ let target_include_dir_fixed = target_dir.join(INCLUDE_DIRNAME);
+
+ // The directory to read source files from.
+ let source_dir = crate_dir.join(SOURCE_DIRNAME);
+
+ let headers = glob::glob(source_include_dir.join("**/*.hpp").to_str().unwrap())
+ .unwrap()
+ .collect::, _>>()
+ .unwrap();
+
+ let compilation_units = glob::glob(source_dir.join("**/*.cpp").to_str().unwrap())
+ .unwrap()
+ .collect::, _>>()
+ .unwrap();
+
+ // Tell Cargo that if the given file changes, to rerun this build script.
+ println!("cargo::rerun-if-changed={INCLUDE_DIRNAME}");
+ println!("cargo::rerun-if-changed={SOURCE_DIRNAME}");
+ println!("cargo::rerun-if-changed=src");
+ println!("cargo::rerun-if-changed=Cargo.toml");
+
+ // Cargo build script metadata, used by dependents' build scripts.
+ // The root directory containing the library archive.
+ println!("cargo::metadata=root={}", out_dir.to_str().unwrap());
+
+ // The include path defining the library's API.
+ println!("cargo::metadata=include={}", target_include_dir.to_str().unwrap());
+
+ // Generate a header containing bindings to the crate.
+ match cbindgen::Builder::new()
+ .with_pragma_once(true)
+ .with_autogen_warning(AUTOGEN_WARNING)
+ .with_no_includes()
+ .with_sys_include("cstdint")
+ .with_parse_deps(true)
+ .with_parse_include(&[
+ "sp1-stark",
+ "sp1-primitives",
+ "sp1-core-machine",
+ "p3-baby-bear",
+ "sp1-core-executor",
+ ])
+ .with_parse_extra_bindings(&["sp1-stark", "sp1-primitives", "p3-baby-bear"])
+ .rename_item("BabyBear", "BabyBearP3")
+ .include_item("MemoryRecord") // Just for convenience. Not exposed, so we need to manually do this.
+ .include_item("SyscallCode") // Required for populating the CPU columns for ECALL.
+ .include_item("SepticExtension")
+ .include_item("SepticCurve")
+ .include_item("MemoryLocalCols")
+ .include_item("MEMORY_LOCAL_INITIAL_DIGEST_POS")
+ .include_item("Ghost")
+ .include_item("MemoryInitCols")
+ .include_item("MemoryInitializeFinalizeEvent")
+ .with_namespace("sp1_core_machine_sys")
+ .with_crate(crate_dir)
+ .generate()
+ {
+ Ok(bindings) => {
+ // Write the bindings to the target include directory.
+ let header_path = target_include_dir.join(cbindgen_hpp);
+ if bindings.write_to_file(&header_path) {
+ // Symlink the header to the fixed include directory.
+ rel_symlink_file(header_path, target_include_dir_fixed.join(cbindgen_hpp));
+ }
+ }
+ Err(cbindgen::Error::ParseSyntaxError { .. }) => {} // Ignore parse errors so rust-analyzer can run.
+ Err(e) => panic!("{:?}", e),
+ }
+
+ // Copy the headers to the include directory and symlink them to the fixed include directory.
+ for header in &headers {
+ // Get the path of the header relative to the source include directory.
+ let relpath = diff_paths(header, &source_include_dir).unwrap();
+
+ // Let the destination path be the same place relative to the target include directory.
+ let dst = target_include_dir.join(&relpath);
+
+ // Create the parent directory if it does not exist.
+ if let Some(parent) = dst.parent() {
+ fs::create_dir_all(parent).unwrap();
+ }
+ fs::copy(header, &dst).unwrap();
+ rel_symlink_file(dst, target_include_dir_fixed.join(relpath));
+ }
+
+ // Use the `cc` crate to build the library and statically link it to the crate.
+ let mut cc_builder = cc::Build::new();
+ cc_builder.files(&compilation_units).include(target_include_dir);
+ cc_builder.cpp(true).std("c++20");
+ cc_builder.compile(LIB_NAME)
+ }
+
+ /// Place a relative symlink pointing to `original` at `link`.
+ fn rel_symlink_file(original: P, link: Q)
+ where
+ P: AsRef,
+ Q: AsRef,
+ {
+ #[cfg(unix)]
+ use os::unix::fs::symlink;
+ #[cfg(windows)]
+ use os::windows::fs::symlink_file as symlink;
+
+ let target_dir = link.as_ref().parent().unwrap();
+ fs::create_dir_all(target_dir).unwrap();
+ let _ = fs::remove_file(&link);
+ let relpath = diff_paths(original, target_dir).unwrap();
+ symlink(relpath, link).unwrap();
+ }
+}
diff --git a/crates/core/machine/cpp/extern.cpp b/crates/core/machine/cpp/extern.cpp
new file mode 100644
index 0000000000..509f5998a7
--- /dev/null
+++ b/crates/core/machine/cpp/extern.cpp
@@ -0,0 +1,28 @@
+#include "bb31_t.hpp"
+#include "bb31_septic_extension_t.hpp"
+#include "sys.hpp"
+
+namespace sp1_core_machine_sys {
+extern void add_sub_event_to_row_babybear(
+ const AluEvent* event,
+ AddSubCols* cols
+) {
+ AddSubCols* cols_bb31 = reinterpret_cast*>(cols);
+ add_sub::event_to_row(*event, *cols_bb31);
+}
+
+extern void memory_local_event_to_row_babybear(const MemoryLocalEvent* event, SingleMemoryLocal* cols) {
+ SingleMemoryLocal* cols_bb31 = reinterpret_cast*>(cols);
+ memory_local::event_to_row(event, cols_bb31);
+}
+
+extern void memory_global_event_to_row_babybear(const MemoryInitializeFinalizeEvent* event, const bool is_receive, MemoryInitCols* cols) {
+ MemoryInitCols* cols_bb31 = reinterpret_cast*>(cols);
+ memory_global::event_to_row(event, is_receive, cols_bb31);
+}
+
+extern void syscall_event_to_row_babybear(const SyscallEvent* event, const bool is_receive, SyscallCols* cols) {
+ SyscallCols* cols_bb31 = reinterpret_cast*>(cols);
+ syscall::event_to_row(event, is_receive, cols_bb31);
+}
+} // namespace sp1_core_machine_sys
diff --git a/crates/core/machine/include/add_sub.hpp b/crates/core/machine/include/add_sub.hpp
new file mode 100644
index 0000000000..ee98c21b4f
--- /dev/null
+++ b/crates/core/machine/include/add_sub.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::add_sub {
+template
+__SP1_HOSTDEV__ __SP1_INLINE__ uint32_t
+populate(AddOperation& op, const uint32_t a_u32, const uint32_t b_u32) {
+ array_t a = u32_to_le_bytes(a_u32);
+ array_t b = u32_to_le_bytes(b_u32);
+ bool carry = a[0] + b[0] > 0xFF;
+ op.carry[0] = F::from_bool(carry).val;
+ carry = a[1] + b[1] + carry > 0xFF;
+ op.carry[1] = F::from_bool(carry).val;
+ carry = a[2] + b[2] + carry > 0xFF;
+ op.carry[2] = F::from_bool(carry).val;
+
+ uint32_t expected = a_u32 + b_u32;
+ write_word_from_u32_v2(op.value, expected);
+ return expected;
+}
+
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, AddSubCols& cols) {
+ bool is_add = event.opcode == Opcode::ADD;
+ cols.shard = F::from_canonical_u32(event.shard);
+ cols.is_add = F::from_bool(is_add);
+ cols.is_sub = F::from_bool(!is_add);
+
+ auto operand_1 = is_add ? event.b : event.a;
+ auto operand_2 = event.c;
+
+ populate(cols.add_operation, operand_1, operand_2);
+ write_word_from_u32_v2(cols.operand_1, operand_1);
+ write_word_from_u32_v2(cols.operand_2, operand_2);
+}
+} // namespace sp1::add_sub
\ No newline at end of file
diff --git a/crates/core/machine/include/bb31_septic_extension_t.hpp b/crates/core/machine/include/bb31_septic_extension_t.hpp
new file mode 100644
index 0000000000..9737d8bb12
--- /dev/null
+++ b/crates/core/machine/include/bb31_septic_extension_t.hpp
@@ -0,0 +1,511 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "bb31_t.hpp"
+#include
+
+#ifdef __CUDA_ARCH__
+#define FUN __host__ __device__
+#endif
+#ifndef __CUDA_ARCH__
+#define FUN inline
+#endif
+
+class bb31_cipolla_t {
+ public:
+ bb31_t real;
+ bb31_t imag;
+
+ FUN bb31_cipolla_t(bb31_t real, bb31_t imag) {
+ this->real = bb31_t(real);
+ this->imag = bb31_t(imag);
+ }
+
+ FUN static bb31_cipolla_t one() {
+ return bb31_cipolla_t(bb31_t::one(), bb31_t::zero());
+ }
+
+ FUN bb31_cipolla_t mul_ext(bb31_cipolla_t other, bb31_t nonresidue) {
+ bb31_t new_real = real * other.real + nonresidue * imag * other.imag;
+ bb31_t new_imag = real * other.imag + imag * other.real;
+ return bb31_cipolla_t(new_real, new_imag);
+ }
+
+ FUN bb31_cipolla_t pow(uint32_t exponent, bb31_t nonresidue) {
+ bb31_cipolla_t result = bb31_cipolla_t::one();
+ bb31_cipolla_t base = *this;
+
+ while(exponent) {
+ if(exponent & 1) {
+ result = result.mul_ext(base, nonresidue);
+ }
+ exponent >>= 1;
+ base = base.mul_ext(base, nonresidue);
+ }
+
+ return result;
+ }
+};
+
+namespace constants {
+ #ifdef __CUDA_ARCH__
+ __constant__ constexpr const bb31_t frobenius_const[49] = {
+ bb31_t(int(1)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)),
+ bb31_t(int(954599710)), bb31_t(int(1359279693)), bb31_t(int(566669999)), bb31_t(int(1982781815)), bb31_t(int(1735718361)), bb31_t(int(1174868538)), bb31_t(int(1120871770)),
+ bb31_t(int(862825265)), bb31_t(int(597046311)), bb31_t(int(978840770)), bb31_t(int(1790138282)), bb31_t(int(1044777201)), bb31_t(int(835869808)), bb31_t(int(1342179023)),
+ bb31_t(int(596273169)), bb31_t(int(658837454)), bb31_t(int(1515468261)), bb31_t(int(367059247)), bb31_t(int(781278880)), bb31_t(int(1544222616)), bb31_t(int(155490465)),
+ bb31_t(int(557608863)), bb31_t(int(1173670028)), bb31_t(int(1749546888)), bb31_t(int(1086464137)), bb31_t(int(803900099)), bb31_t(int(1288818584)), bb31_t(int(1184677604)),
+ bb31_t(int(763416381)), bb31_t(int(1252567168)), bb31_t(int(628856225)), bb31_t(int(1771903394)), bb31_t(int(650712211)), bb31_t(int(19417363)), bb31_t(int(57990258)),
+ bb31_t(int(1734711039)), bb31_t(int(1749813853)), bb31_t(int(1227235221)), bb31_t(int(1707730636)), bb31_t(int(424560395)), bb31_t(int(1007029514)), bb31_t(int(498034669)),
+ };
+
+ __constant__ constexpr const bb31_t double_frobenius_const[49] = {
+ bb31_t(int(1)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)),
+ bb31_t(int(1013489358)), bb31_t(int(1619071628)), bb31_t(int(304593143)), bb31_t(int(1949397349)), bb31_t(int(1564307636)), bb31_t(int(327761151)), bb31_t(int(415430835)),
+ bb31_t(int(209824426)), bb31_t(int(1313900768)), bb31_t(int(38410482)), bb31_t(int(256593180)), bb31_t(int(1708830551)), bb31_t(int(1244995038)), bb31_t(int(1555324019)),
+ bb31_t(int(1475628651)), bb31_t(int(777565847)), bb31_t(int(704492386)), bb31_t(int(1218528120)), bb31_t(int(1245363405)), bb31_t(int(475884575)), bb31_t(int(649166061)),
+ bb31_t(int(550038364)), bb31_t(int(948935655)), bb31_t(int(68722023)), bb31_t(int(1251345762)), bb31_t(int(1692456177)), bb31_t(int(1177958698)), bb31_t(int(350232928)),
+ bb31_t(int(882720258)), bb31_t(int(821925756)), bb31_t(int(199955840)), bb31_t(int(812002876)), bb31_t(int(1484951277)), bb31_t(int(1063138035)), bb31_t(int(491712810)),
+ bb31_t(int(738287111)), bb31_t(int(1955364991)), bb31_t(int(552724293)), bb31_t(int(1175775744)), bb31_t(int(341623997)), bb31_t(int(1454022463)), bb31_t(int(408193320))
+ };
+
+ __constant__ constexpr const bb31_t A_EC_LOGUP[7] = {bb31_t(int(0x31415926)), bb31_t(int(0x53589793)), bb31_t(int(0x23846264)), bb31_t(int(0x33832795)), bb31_t(int(0x02884197)), bb31_t(int(0x16939937)), bb31_t(int(0x51058209))};
+
+ __constant__ constexpr const bb31_t B_EC_LOGUP[7] = {bb31_t(int(0x74944592)), bb31_t(int(0x30781640)), bb31_t(int(0x62862089)), bb31_t(int(0x9862803)), bb31_t(int(0x48253421)), bb31_t(int(0x17067982)), bb31_t(int(0x14808651))};
+
+ __constant__ constexpr const bb31_t dummy_x[7] = {bb31_t(int(0x2738281)), bb31_t(int(0x8284590)), bb31_t(int(0x4523536)), bb31_t(int(0x0287471)), bb31_t(int(0x3526624)), bb31_t(int(0x9775724)), bb31_t(int(0x7093699))};
+ __constant__ constexpr const bb31_t dummy_y[7] = {bb31_t(int(48041908)), bb31_t(int(550064556)), bb31_t(int(415267377)), bb31_t(int(1726976249)), bb31_t(int(1253299140)), bb31_t(int(209439863)), bb31_t(int(1302309485))};
+
+ __constant__ constexpr bb31_t start_x[7] = {bb31_t(int(0x1434213)), bb31_t(int(0x5623730)), bb31_t(int(0x9504880)), bb31_t(int(0x1688724)), bb31_t(int(0x2096980)), bb31_t(int(0x7856967)), bb31_t(int(0x1875376))};
+ __constant__ constexpr bb31_t start_y[7] = {bb31_t(int(885797405)), bb31_t(int(1130275556)), bb31_t(int(567836311)), bb31_t(int(52700240)), bb31_t(int(239639200)), bb31_t(int(442612155)), bb31_t(int(1839439733))};
+
+ #endif
+
+ #ifndef __CUDA_ARCH__
+ static constexpr const bb31_t frobenius_const[49] = {
+ bb31_t(int(1)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)),
+ bb31_t(int(954599710)), bb31_t(int(1359279693)), bb31_t(int(566669999)), bb31_t(int(1982781815)), bb31_t(int(1735718361)), bb31_t(int(1174868538)), bb31_t(int(1120871770)),
+ bb31_t(int(862825265)), bb31_t(int(597046311)), bb31_t(int(978840770)), bb31_t(int(1790138282)), bb31_t(int(1044777201)), bb31_t(int(835869808)), bb31_t(int(1342179023)),
+ bb31_t(int(596273169)), bb31_t(int(658837454)), bb31_t(int(1515468261)), bb31_t(int(367059247)), bb31_t(int(781278880)), bb31_t(int(1544222616)), bb31_t(int(155490465)),
+ bb31_t(int(557608863)), bb31_t(int(1173670028)), bb31_t(int(1749546888)), bb31_t(int(1086464137)), bb31_t(int(803900099)), bb31_t(int(1288818584)), bb31_t(int(1184677604)),
+ bb31_t(int(763416381)), bb31_t(int(1252567168)), bb31_t(int(628856225)), bb31_t(int(1771903394)), bb31_t(int(650712211)), bb31_t(int(19417363)), bb31_t(int(57990258)),
+ bb31_t(int(1734711039)), bb31_t(int(1749813853)), bb31_t(int(1227235221)), bb31_t(int(1707730636)), bb31_t(int(424560395)), bb31_t(int(1007029514)), bb31_t(int(498034669))
+ };
+
+ static constexpr const bb31_t double_frobenius_const[49] = {
+ bb31_t(int(1)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)), bb31_t(int(0)),
+ bb31_t(int(1013489358)), bb31_t(int(1619071628)), bb31_t(int(304593143)), bb31_t(int(1949397349)), bb31_t(int(1564307636)), bb31_t(int(327761151)), bb31_t(int(415430835)),
+ bb31_t(int(209824426)), bb31_t(int(1313900768)), bb31_t(int(38410482)), bb31_t(int(256593180)), bb31_t(int(1708830551)), bb31_t(int(1244995038)), bb31_t(int(1555324019)),
+ bb31_t(int(1475628651)), bb31_t(int(777565847)), bb31_t(int(704492386)), bb31_t(int(1218528120)), bb31_t(int(1245363405)), bb31_t(int(475884575)), bb31_t(int(649166061)),
+ bb31_t(int(550038364)), bb31_t(int(948935655)), bb31_t(int(68722023)), bb31_t(int(1251345762)), bb31_t(int(1692456177)), bb31_t(int(1177958698)), bb31_t(int(350232928)),
+ bb31_t(int(882720258)), bb31_t(int(821925756)), bb31_t(int(199955840)), bb31_t(int(812002876)), bb31_t(int(1484951277)), bb31_t(int(1063138035)), bb31_t(int(491712810)),
+ bb31_t(int(738287111)), bb31_t(int(1955364991)), bb31_t(int(552724293)), bb31_t(int(1175775744)), bb31_t(int(341623997)), bb31_t(int(1454022463)), bb31_t(int(408193320))
+ };
+
+ static constexpr const bb31_t A_EC_LOGUP[7] = {bb31_t(int(0x31415926)), bb31_t(int(0x53589793)), bb31_t(int(0x23846264)), bb31_t(int(0x33832795)), bb31_t(int(0x02884197)), bb31_t(int(0x16939937)), bb31_t(int(0x51058209))};
+ static constexpr const bb31_t B_EC_LOGUP[7] = {bb31_t(int(0x74944592)), bb31_t(int(0x30781640)), bb31_t(int(0x62862089)), bb31_t(int(0x9862803)), bb31_t(int(0x48253421)), bb31_t(int(0x17067982)), bb31_t(int(0x14808651))};
+
+ static constexpr bb31_t dummy_x[7] = {bb31_t(int(0x2738281)), bb31_t(int(0x8284590)), bb31_t(int(0x4523536)), bb31_t(int(0x0287471)), bb31_t(int(0x3526624)), bb31_t(int(0x9775724)), bb31_t(int(0x7093699))};
+ static constexpr bb31_t dummy_y[7] = {bb31_t(int(48041908)), bb31_t(int(550064556)), bb31_t(int(415267377)), bb31_t(int(1726976249)), bb31_t(int(1253299140)), bb31_t(int(209439863)), bb31_t(int(1302309485))};
+
+ static constexpr bb31_t start_x[7] = {bb31_t(int(0x1434213)), bb31_t(int(0x5623730)), bb31_t(int(0x9504880)), bb31_t(int(0x1688724)), bb31_t(int(0x2096980)), bb31_t(int(0x7856967)), bb31_t(int(0x1875376))};
+ static constexpr bb31_t start_y[7] = {bb31_t(int(885797405)), bb31_t(int(1130275556)), bb31_t(int(567836311)), bb31_t(int(52700240)), bb31_t(int(239639200)), bb31_t(int(442612155)), bb31_t(int(1839439733))};
+
+ #endif
+}
+
+class bb31_septic_extension_t {
+ // The value of BabyBear septic extension element.
+ public:
+ bb31_t value[7];
+ static constexpr const bb31_t* frobenius_const = constants::frobenius_const;
+ static constexpr const bb31_t* double_frobenius_const = constants::double_frobenius_const;
+ static constexpr const bb31_t* A_EC_LOGUP = constants::A_EC_LOGUP;
+ static constexpr const bb31_t* B_EC_LOGUP = constants::B_EC_LOGUP;
+
+ FUN bb31_septic_extension_t() {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->value[i] = bb31_t(0);
+ }
+ }
+
+ FUN bb31_septic_extension_t(bb31_t value) {
+ this->value[0] = value;
+ for (uintptr_t i = 1 ; i < 7 ; i++) {
+ this->value[i] = bb31_t(0);
+ }
+ }
+
+ FUN bb31_septic_extension_t(bb31_t value[7]) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->value[i] = value[i];
+ }
+ }
+
+ FUN bb31_septic_extension_t(const bb31_t value[7]) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->value[i] = value[i];
+ }
+ }
+
+ static FUN bb31_septic_extension_t zero() {
+ return bb31_septic_extension_t();
+ }
+
+ static FUN bb31_septic_extension_t one() {
+ return bb31_septic_extension_t(bb31_t::one());
+ }
+
+ static FUN bb31_septic_extension_t two() {
+ return bb31_septic_extension_t(bb31_t::two());
+ }
+
+ static FUN bb31_septic_extension_t from_canonical_u32(uint32_t n) {
+ return bb31_septic_extension_t(bb31_t::from_canonical_u32(n));
+ }
+
+ FUN bb31_septic_extension_t& operator+=(const bb31_t b) {
+ value[0] += b;
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator+(bb31_septic_extension_t a, const bb31_t b) {
+ return a += b;
+ }
+
+ FUN bb31_septic_extension_t& operator+=(const bb31_septic_extension_t b) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ value[i] += b.value[i];
+ }
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator+(bb31_septic_extension_t a, const bb31_septic_extension_t b) {
+ return a += b;
+ }
+
+ FUN bb31_septic_extension_t& operator-=(const bb31_t b) {
+ value[0] -= b;
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator-(bb31_septic_extension_t a, const bb31_t b) {
+ return a -= b;
+ }
+
+ FUN bb31_septic_extension_t& operator-=(const bb31_septic_extension_t b) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ value[i] -= b.value[i];
+ }
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator-(bb31_septic_extension_t a, const bb31_septic_extension_t b) {
+ return a -= b;
+ }
+
+ FUN bb31_septic_extension_t& operator*=(const bb31_t b) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ value[i] *= b;
+ }
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator*(bb31_septic_extension_t a, const bb31_t b) {
+ return a *= b;
+ }
+
+ FUN bb31_septic_extension_t& operator*=(const bb31_septic_extension_t b) {
+ {
+ bb31_t res[13] = {};
+ for(uintptr_t i = 0 ; i < 13 ; i++) {
+ res[i] = bb31_t::zero();
+ }
+ for(uintptr_t i = 0 ; i < 7 ; i++) {
+ for(uintptr_t j = 0 ; j < 7 ; j++) {
+ res[i + j] += value[i] * b.value[j];
+ }
+ }
+ for(uintptr_t i = 7 ; i < 13 ; i++) {
+ res[i - 7] += res[i] * bb31_t::from_canonical_u32(5);
+ res[i - 6] += res[i] * bb31_t::from_canonical_u32(2);
+ }
+ for(uintptr_t i = 0 ; i < 7 ; i++) {
+ value[i] = res[i];
+ }
+ }
+ return *this;
+ }
+
+ friend FUN bb31_septic_extension_t operator*(bb31_septic_extension_t a, const bb31_septic_extension_t b) {
+ return a *= b;
+ }
+
+ FUN bool operator==(const bb31_septic_extension_t rhs) const {
+ for(uintptr_t i = 0 ; i < 7 ; i++) {
+ if(value[i] != rhs.value[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ FUN bb31_septic_extension_t frobenius() const {
+ bb31_t res[7] = {};
+ res[0] = value[0];
+ for(uintptr_t i = 1 ; i < 7 ; i++) {
+ res[i] = bb31_t::zero();
+ }
+ for(uintptr_t i = 1 ; i < 7 ; i++) {
+ for(uintptr_t j = 0 ; j < 7 ; j++) {
+ res[j] += value[i] * frobenius_const[7 * i + j];
+ }
+ }
+ return bb31_septic_extension_t(res);
+
+ }
+
+ FUN bb31_septic_extension_t double_frobenius() const {
+ bb31_t res[7] = {};
+ res[0] = value[0];
+ for(uintptr_t i = 1 ; i < 7 ; i++) {
+ res[i] = bb31_t::zero();
+ }
+ for(uintptr_t i = 1 ; i < 7 ; i++) {
+ for(uintptr_t j = 0 ; j < 7 ; j++) {
+ res[j] += value[i] * double_frobenius_const[7 * i + j];
+ }
+ }
+ return bb31_septic_extension_t(res);
+
+ }
+
+ FUN bb31_septic_extension_t pow_r_1() const {
+ bb31_septic_extension_t base = frobenius();
+ base *= double_frobenius();
+ bb31_septic_extension_t base_p2 = base.double_frobenius();
+ bb31_septic_extension_t base_p4 = base_p2.double_frobenius();
+ return base * base_p2 * base_p4;
+ }
+
+ FUN bb31_t pow_r() const {
+ bb31_septic_extension_t pow_r1 = pow_r_1();
+ bb31_septic_extension_t pow_r = pow_r1 * *this;
+ return pow_r.value[0];
+ }
+
+ FUN bb31_septic_extension_t reciprocal() const {
+ bb31_septic_extension_t pow_r1 = pow_r_1();
+ bb31_septic_extension_t pow_r = pow_r1 * *this;
+ return pow_r1 * pow_r.value[0].reciprocal();
+ }
+
+ friend FUN bb31_septic_extension_t operator/(bb31_septic_extension_t a, bb31_septic_extension_t b) {
+ return a * b.reciprocal();
+ }
+
+ FUN bb31_septic_extension_t& operator/=(const bb31_septic_extension_t a) {
+ return *this *= a.reciprocal();
+ }
+
+ FUN bb31_septic_extension_t sqrt(bb31_t pow_r) const {
+ if (*this == bb31_septic_extension_t::zero()) {
+ return *this;
+ }
+
+ bb31_septic_extension_t n_iter = *this;
+ bb31_septic_extension_t n_power = *this;
+ for(uintptr_t i = 1 ; i < 30 ; i++) {
+ n_iter *= n_iter;
+ if(i >= 26) {
+ n_power *= n_iter;
+ }
+ }
+
+ bb31_septic_extension_t n_frobenius = n_power.frobenius();
+ bb31_septic_extension_t denominator = n_frobenius;
+
+ n_frobenius = n_frobenius.double_frobenius();
+ denominator *= n_frobenius;
+ n_frobenius = n_frobenius.double_frobenius();
+ denominator *= n_frobenius;
+ denominator *= *this;
+
+ bb31_t base = pow_r.reciprocal();
+ bb31_t g = bb31_t::from_canonical_u32(31);
+ bb31_t a = bb31_t::one();
+ bb31_t nonresidue = bb31_t::one() - base;
+
+ while (true) {
+ bb31_t is_square = nonresidue ^ 1006632960;
+ if (is_square != bb31_t::one()) {
+ break;
+ }
+ a *= g;
+ nonresidue = a.square() - base;
+ }
+
+ bb31_cipolla_t x = bb31_cipolla_t(a, bb31_t::one());
+ x = x.pow(1006632961, nonresidue);
+
+ return denominator * x.real;
+ }
+
+ FUN bb31_septic_extension_t universal_hash() const {
+ return *this * bb31_septic_extension_t(A_EC_LOGUP) + bb31_septic_extension_t(B_EC_LOGUP);
+ }
+
+ FUN bb31_septic_extension_t curve_formula() const {
+ bb31_septic_extension_t result = *this * *this * *this;
+ result += *this;
+ result += *this;
+ result.value[5] += bb31_t::from_canonical_u32(26);
+ return result;
+ }
+
+ FUN bool is_receive() const {
+ uint32_t limb = value[6].as_canonical_u32();
+ return 1 <= limb && limb <= (bb31_t::MOD - 1) / 2;
+ }
+
+ FUN bool is_send() const {
+ uint32_t limb = value[6].as_canonical_u32();
+ return (bb31_t::MOD + 1) / 2 <= limb && limb <= (bb31_t::MOD - 1);
+ }
+
+ FUN bool is_exception() const {
+ return value[6] == bb31_t::zero();
+ }
+};
+
+
+class bb31_septic_curve_t {
+ public:
+ bb31_septic_extension_t x;
+ bb31_septic_extension_t y;
+
+ static constexpr const bb31_t* dummy_x = constants::dummy_x;
+ static constexpr const bb31_t* dummy_y = constants::dummy_y;
+ static constexpr const bb31_t* start_x = constants::start_x;
+ static constexpr const bb31_t* start_y = constants::start_y;
+
+ FUN bb31_septic_curve_t() {
+ this->x = bb31_septic_extension_t::zero();
+ this->y = bb31_septic_extension_t::zero();
+ }
+
+ FUN bb31_septic_curve_t(bb31_septic_extension_t x, bb31_septic_extension_t y) {
+ this->x = x;
+ this->y = y;
+ }
+
+ FUN bb31_septic_curve_t(bb31_t value[14]) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->x.value[i] = value[i];
+ }
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->y.value[i] = value[i + 7];
+ }
+ }
+
+ FUN bb31_septic_curve_t(bb31_t value_x[7], bb31_t value_y[7]) {
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ this->x.value[i] = value_x[i];
+ this->y.value[i] = value_y[i];
+ }
+ }
+
+ static FUN bb31_septic_curve_t dummy_point() {
+ bb31_septic_extension_t x;
+ bb31_septic_extension_t y;
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ x.value[i] = dummy_x[i];
+ y.value[i] = dummy_y[i];
+ }
+ return bb31_septic_curve_t(x, y);
+ }
+
+ static FUN bb31_septic_curve_t start_point() {
+ bb31_septic_extension_t x;
+ bb31_septic_extension_t y;
+ for (uintptr_t i = 0 ; i < 7 ; i++) {
+ x.value[i] = start_x[i];
+ y.value[i] = start_y[i];
+ }
+ return bb31_septic_curve_t(x, y);
+ }
+
+ FUN bool is_infinity() const {
+ return x == bb31_septic_extension_t::zero() && y == bb31_septic_extension_t::zero();
+ }
+
+ FUN bb31_septic_curve_t& operator+=(const bb31_septic_curve_t b) {
+ if (b.is_infinity()) {
+ return *this;
+ }
+ if (is_infinity()) {
+ x = b.x;
+ y = b.y;
+ return *this;
+ }
+ if (x == b.x) {
+ if (y == b.y) {
+ bb31_septic_extension_t slope = (x * x * bb31_t::from_canonical_u8(3) + bb31_t::two()) / (y * bb31_t::two());
+ bb31_septic_extension_t result_x = slope * slope - x - b.x;
+ bb31_septic_extension_t result_y = slope * (x - result_x) - y;
+ x = result_x;
+ y = result_y;
+ return *this;
+ }
+ else {
+ x = bb31_septic_extension_t::zero();
+ y = bb31_septic_extension_t::zero();
+ return *this;
+ }
+ }
+ else {
+ bb31_septic_extension_t slope = (b.y - y) / (b.x - x);
+ bb31_septic_extension_t result_x = slope * slope - x - b.x;
+ bb31_septic_extension_t result_y = slope * (x - result_x) - y;
+ x = result_x;
+ y = result_y;
+ return *this;
+ }
+ }
+
+ friend FUN bb31_septic_curve_t operator+(bb31_septic_curve_t a, const bb31_septic_curve_t b) {
+ return a += b;
+ }
+
+ static FUN bb31_septic_extension_t sum_checker_x(
+ const bb31_septic_curve_t& p1,
+ const bb31_septic_curve_t& p2,
+ const bb31_septic_curve_t& p3
+ ) {
+ bb31_septic_extension_t x_diff = p2.x - p1.x;
+ bb31_septic_extension_t y_diff = p2.y - p1.y;
+ return (p1.x + p2.x + p3.x) * x_diff * x_diff - y_diff * y_diff;
+ }
+};
+
+class bb31_septic_digest_t {
+ public:
+ bb31_septic_curve_t point;
+
+ FUN bb31_septic_digest_t() {
+ this->point = bb31_septic_curve_t();
+ }
+
+ FUN bb31_septic_digest_t(bb31_t value[14]) {
+ this->point = bb31_septic_curve_t(value);
+ }
+
+ FUN bb31_septic_digest_t(bb31_septic_extension_t x, bb31_septic_extension_t y) {
+ this->point = bb31_septic_curve_t(x, y);
+ }
+
+ FUN bb31_septic_digest_t(bb31_septic_curve_t point) {
+ this->point = point;
+ }
+};
+
diff --git a/crates/core/machine/include/bb31_t.hpp b/crates/core/machine/include/bb31_t.hpp
new file mode 100644
index 0000000000..387456d422
--- /dev/null
+++ b/crates/core/machine/include/bb31_t.hpp
@@ -0,0 +1,640 @@
+// Modified by Succinct Labs
+// Copyright Supranational LLC
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include
+#include
+
+#ifdef __CUDA_ARCH__
+
+#define inline __device__ __forceinline__
+#ifdef __GNUC__
+#define asm __asm__ __volatile__
+#else
+#define asm asm volatile
+#endif
+
+class bb31_t {
+ public:
+ using mem_t = bb31_t;
+ uint32_t val;
+ static const uint32_t DEGREE = 1;
+ static const uint32_t NBITS = 31;
+ static const uint32_t MOD = 0x78000001u;
+ static const uint32_t M = 0x77ffffffu;
+ static const uint32_t RR = 0x45dddde3u;
+ static const uint32_t ONE = 0x0ffffffeu;
+ static const uint32_t MONTY_BITS = 32;
+ static const uint32_t MONTY_MU = 0x88000001;
+ static const uint32_t MONTY_MASK = ((1ULL << MONTY_BITS) - 1);
+
+ static constexpr size_t __device__ bit_length() { return 31; }
+
+ inline uint32_t& operator[](size_t i) { return val; }
+
+ inline uint32_t& operator*() { return val; }
+
+ inline const uint32_t& operator[](size_t i) const { return val; }
+
+ inline uint32_t operator*() const { return val; }
+
+ inline size_t len() const { return 1; }
+
+ inline bb31_t() {}
+
+ inline bb31_t(const uint32_t a) { val = a; }
+
+ inline bb31_t(const uint32_t* p) { val = *p; }
+
+ inline constexpr bb31_t(int a) : val(((uint64_t)a << 32) % MOD) {}
+
+ static inline const bb31_t zero() { return bb31_t(0); }
+
+ static inline const bb31_t one() { return bb31_t(ONE); }
+
+ static inline const bb31_t two() { return from_canonical_u32(2); }
+
+ static inline uint32_t to_monty(uint32_t x) {
+ return (((uint64_t)x << MONTY_BITS) % MOD);
+ }
+
+ static inline uint32_t monty_reduce(uint64_t x) {
+ uint64_t t = (x * (uint64_t)MONTY_MU) & (uint64_t)MONTY_MASK;
+ uint64_t u = t * (uint64_t)MOD;
+ uint64_t x_sub_u = x - u;
+ bool over = x < u;
+ uint32_t x_sub_u_hi = (uint32_t)(x_sub_u >> MONTY_BITS);
+ uint32_t corr = over ? MOD : 0;
+ return x_sub_u_hi + corr;
+ }
+
+ static inline bb31_t from_canonical_u32(uint32_t x) {
+ return bb31_t(to_monty(x));
+ }
+
+ static inline bb31_t from_canonical_u16(uint16_t x) {
+ return from_canonical_u32((uint32_t)x);
+ }
+
+ static inline bb31_t from_canonical_u8(uint8_t x) {
+ return from_canonical_u32((uint32_t)x);
+ }
+
+ static inline bb31_t from_bool(bool x) { return bb31_t(x * one().val); }
+
+ inline uint32_t as_canonical_u32() const {
+ return monty_reduce((uint64_t)val);
+ }
+
+ inline bb31_t exp_power_of_two(size_t log_power) {
+ bb31_t ret = *this;
+ for (size_t i = 0; i < log_power; i++) {
+ ret *= ret;
+ }
+ return ret;
+ }
+
+ inline bb31_t& operator+=(const bb31_t b) {
+ val += b.val;
+ final_sub(val);
+
+ return *this;
+ }
+
+ friend inline bb31_t operator+(bb31_t a, const bb31_t b) { return a += b; }
+
+ inline bb31_t& operator<<=(uint32_t l) {
+ while (l--) {
+ val <<= 1;
+ final_sub(val);
+ }
+
+ return *this;
+ }
+
+ friend inline bb31_t operator<<(bb31_t a, uint32_t l) { return a <<= l; }
+
+ inline bb31_t& operator>>=(uint32_t r) {
+ while (r--) {
+ val += val & 1 ? MOD : 0;
+ val >>= 1;
+ }
+
+ return *this;
+ }
+
+ friend inline bb31_t operator>>(bb31_t a, uint32_t r) { return a >>= r; }
+
+ inline bb31_t& operator-=(const bb31_t b) {
+ asm("{");
+ asm(".reg.pred %brw;");
+ asm("setp.lt.u32 %brw, %0, %1;" ::"r"(val), "r"(b.val));
+ asm("sub.u32 %0, %0, %1;" : "+r"(val) : "r"(b.val));
+ asm("@%brw add.u32 %0, %0, %1;" : "+r"(val) : "r"(MOD));
+ asm("}");
+
+ return *this;
+ }
+
+ friend inline bb31_t operator-(bb31_t a, const bb31_t b) { return a -= b; }
+
+ inline bb31_t cneg(bool flag) {
+ asm("{");
+ asm(".reg.pred %flag;");
+ asm("setp.ne.u32 %flag, %0, 0;" ::"r"(val));
+ asm("@%flag setp.ne.u32 %flag, %0, 0;" ::"r"((int)flag));
+ asm("@%flag sub.u32 %0, %1, %0;" : "+r"(val) : "r"(MOD));
+ asm("}");
+
+ return *this;
+ }
+
+ static inline bb31_t cneg(bb31_t a, bool flag) { return a.cneg(flag); }
+
+ inline bb31_t operator-() const { return cneg(*this, true); }
+
+ inline bool operator==(const bb31_t rhs) const { return val == rhs.val; }
+
+ inline bool is_one() const { return val == ONE; }
+
+ inline bool is_zero() const { return val == 0; }
+
+ inline void set_to_zero() { val = 0; }
+
+ friend inline bb31_t czero(const bb31_t a, int set_z) {
+ bb31_t ret;
+
+ asm("{");
+ asm(".reg.pred %set_z;");
+ asm("setp.ne.s32 %set_z, %0, 0;" : : "r"(set_z));
+ asm("selp.u32 %0, 0, %1, %set_z;" : "=r"(ret.val) : "r"(a.val));
+ asm("}");
+
+ return ret;
+ }
+
+ static inline bb31_t csel(const bb31_t a, const bb31_t b, int sel_a) {
+ bb31_t ret;
+
+ asm("{");
+ asm(".reg.pred %sel_a;");
+ asm("setp.ne.s32 %sel_a, %0, 0;" ::"r"(sel_a));
+ asm("selp.u32 %0, %1, %2, %sel_a;"
+ : "=r"(ret.val)
+ : "r"(a.val), "r"(b.val));
+ asm("}");
+
+ return ret;
+ }
+
+ private:
+ static inline void final_sub(uint32_t& val) {
+ asm("{");
+ asm(".reg.pred %p;");
+ asm("setp.ge.u32 %p, %0, %1;" ::"r"(val), "r"(MOD));
+ asm("@%p sub.u32 %0, %0, %1;" : "+r"(val) : "r"(MOD));
+ asm("}");
+ }
+
+ inline bb31_t& mul(const bb31_t b) {
+ uint32_t tmp[2], red;
+
+ asm("mul.lo.u32 %0, %2, %3; mul.hi.u32 %1, %2, %3;"
+ : "=r"(tmp[0]), "=r"(tmp[1])
+ : "r"(val), "r"(b.val));
+ asm("mul.lo.u32 %0, %1, %2;" : "=r"(red) : "r"(tmp[0]), "r"(M));
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %4;"
+ : "+r"(tmp[0]), "=r"(val)
+ : "r"(red), "r"(MOD), "r"(tmp[1]));
+
+ final_sub(val);
+
+ return *this;
+ }
+
+ inline uint32_t mul_by_1() const {
+ uint32_t tmp[2], red;
+
+ asm("mul.lo.u32 %0, %1, %2;" : "=r"(red) : "r"(val), "r"(M));
+ asm("mad.lo.cc.u32 %0, %2, %3, %4; madc.hi.u32 %1, %2, %3, 0;"
+ : "=r"(tmp[0]), "=r"(tmp[1])
+ : "r"(red), "r"(MOD), "r"(val));
+ return tmp[1];
+ }
+
+ public:
+ friend inline bb31_t operator*(bb31_t a, const bb31_t b) { return a.mul(b); }
+
+ inline bb31_t& operator*=(const bb31_t a) { return mul(a); }
+
+ // raise to a variable power, variable in respect to threadIdx,
+ // but mind the ^ operator's precedence!
+ inline bb31_t& operator^=(uint32_t p) {
+ bb31_t sqr = *this;
+ *this = csel(val, ONE, p & 1);
+
+#pragma unroll 1
+ while (p >>= 1) {
+ sqr.mul(sqr);
+ if (p & 1)
+ mul(sqr);
+ }
+
+ return *this;
+ }
+
+ friend inline bb31_t operator^(bb31_t a, uint32_t p) {
+ return a ^= p;
+ }
+
+ inline bb31_t operator()(uint32_t p) {
+ return *this ^ p;
+ }
+
+ // raise to a constant power, e.g. x^7, to be unrolled at compile time
+ inline bb31_t& operator^=(int p) {
+ if (p < 2)
+ asm("trap;");
+
+ bb31_t sqr = *this;
+ if ((p & 1) == 0) {
+ do {
+ sqr.mul(sqr);
+ p >>= 1;
+ } while ((p & 1) == 0);
+ *this = sqr;
+ }
+ for (p >>= 1; p; p >>= 1) {
+ sqr.mul(sqr);
+ if (p & 1)
+ mul(sqr);
+ }
+
+ return *this;
+ }
+
+ friend inline bb31_t operator^(bb31_t a, int p) {
+ return a ^= p;
+ }
+
+ inline bb31_t operator()(int p) {
+ return *this ^ p;
+ }
+
+ inline bb31_t square() { return *this * *this; }
+
+ friend inline bb31_t sqr(bb31_t a) {
+ return a.sqr();
+ }
+
+ inline bb31_t& sqr() {
+ return mul(*this);
+ }
+
+ inline void to() {
+ mul(RR);
+ }
+
+ inline void from() {
+ val = mul_by_1();
+ }
+
+ template
+ static inline bb31_t dot_product(const bb31_t a[T], const bb31_t b[T]) {
+ uint32_t acc[2];
+ size_t i = 1;
+
+ asm("mul.lo.u32 %0, %2, %3; mul.hi.u32 %1, %2, %3;"
+ : "=r"(acc[0]), "=r"(acc[1])
+ : "r"(*a[0]), "r"(*b[0]));
+ if ((T & 1) == 0) {
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i]), "r"(*b[i]));
+ i++;
+ }
+ for (; i < T; i += 2) {
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i]), "r"(*b[i]));
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i + 1]), "r"(*b[i + 1]));
+ final_sub(acc[1]);
+ }
+
+ uint32_t red;
+ asm("mul.lo.u32 %0, %1, %2;" : "=r"(red) : "r"(acc[0]), "r"(M));
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(red), "r"(MOD));
+ final_sub(acc[1]);
+
+ return acc[1];
+ }
+
+ template
+ static inline bb31_t dot_product(bb31_t a0, bb31_t b0, const bb31_t a[T - 1],
+ const bb31_t* b, size_t stride_b = 1) {
+ uint32_t acc[2];
+ size_t i = 0;
+
+ asm("mul.lo.u32 %0, %2, %3; mul.hi.u32 %1, %2, %3;"
+ : "=r"(acc[0]), "=r"(acc[1])
+ : "r"(*a0), "r"(*b0));
+ if ((T & 1) == 0) {
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i]), "r"(*b[0]));
+ i++, b += stride_b;
+ }
+ for (; i < T - 1; i += 2) {
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i]), "r"(*b[0]));
+ b += stride_b;
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(*a[i + 1]), "r"(*b[0]));
+ b += stride_b;
+ final_sub(acc[1]);
+ }
+
+ uint32_t red;
+ asm("mul.lo.u32 %0, %1, %2;" : "=r"(red) : "r"(acc[0]), "r"(M));
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %1;"
+ : "+r"(acc[0]), "+r"(acc[1])
+ : "r"(red), "r"(MOD));
+ final_sub(acc[1]);
+
+ return acc[1];
+ }
+
+ private:
+ static inline bb31_t sqr_n(bb31_t s, uint32_t n) {
+#if 0
+#pragma unroll 2
+ while (n--)
+ s.sqr();
+#else // +20% [for reciprocal()]
+#pragma unroll 2
+ while (n--) {
+ uint32_t tmp[2], red;
+
+ asm("mul.lo.u32 %0, %2, %2; mul.hi.u32 %1, %2, %2;"
+ : "=r"(tmp[0]), "=r"(tmp[1])
+ : "r"(s.val));
+ asm("mul.lo.u32 %0, %1, %2;" : "=r"(red) : "r"(tmp[0]), "r"(M));
+ asm("mad.lo.cc.u32 %0, %2, %3, %0; madc.hi.u32 %1, %2, %3, %4;"
+ : "+r"(tmp[0]), "=r"(s.val)
+ : "r"(red), "r"(MOD), "r"(tmp[1]));
+
+ if (n & 1)
+ final_sub(s.val);
+ }
+#endif
+ return s;
+ }
+
+ static inline bb31_t sqr_n_mul(bb31_t s, uint32_t n, bb31_t m) {
+ s = sqr_n(s, n);
+ s.mul(m);
+
+ return s;
+ }
+
+ public:
+ inline bb31_t reciprocal() const {
+ bb31_t x11, xff, ret = *this;
+
+ x11 = sqr_n_mul(ret, 4, ret); // 0b10001
+ ret = sqr_n_mul(x11, 1, x11); // 0b110011
+ ret = sqr_n_mul(ret, 1, x11); // 0b1110111
+ xff = sqr_n_mul(ret, 1, x11); // 0b11111111
+ ret = sqr_n_mul(ret, 8, xff); // 0b111011111111111
+ ret = sqr_n_mul(ret, 8, xff); // 0b11101111111111111111111
+ ret = sqr_n_mul(ret, 8, xff); // 0b1110111111111111111111111111111
+
+ return ret;
+ }
+
+ friend inline bb31_t operator/(int one, bb31_t a) {
+ if (one != 1)
+ asm("trap;");
+ return a.reciprocal();
+ }
+
+ friend inline bb31_t operator/(bb31_t a, bb31_t b) {
+ return a * b.reciprocal();
+ }
+
+ inline bb31_t& operator/=(const bb31_t a) {
+ return *this *= a.reciprocal();
+ }
+
+ inline bb31_t heptaroot() const {
+ bb31_t x03, x18, x1b, ret = *this;
+
+ x03 = sqr_n_mul(ret, 1, ret); // 0b11
+ x18 = sqr_n(x03, 3); // 0b11000
+ x1b = x18 * x03; // 0b11011
+ ret = x18 * x1b; // 0b110011
+ ret = sqr_n_mul(ret, 6, x1b); // 0b110011011011
+ ret = sqr_n_mul(ret, 6, x1b); // 0b110011011011011011
+ ret = sqr_n_mul(ret, 6, x1b); // 0b110011011011011011011011
+ ret = sqr_n_mul(ret, 6, x1b); // 0b110011011011011011011011011011
+ ret = sqr_n_mul(ret, 1, *this); // 0b1100110110110110110110110110111
+
+ return ret;
+ }
+
+ inline void shfl_bfly(uint32_t laneMask) {
+ val = __shfl_xor_sync(0xFFFFFFFF, val, laneMask);
+ }
+};
+
+#undef inline
+#undef asm
+// # endif // __CUDA__ARCH__
+
+#else
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+class bb31_t {
+ private:
+ static const uint32_t M = 0x77ffffffu;
+ static const uint32_t RR = 0x45dddde3u;
+ static const uint32_t ONE = 0x0ffffffeu;
+ static const uint32_t MONTY_BITS = 32;
+ static const uint32_t MONTY_MU = 0x88000001;
+ static const uint32_t MONTY_MASK = ((1ULL << MONTY_BITS) - 1);
+
+ public:
+ using mem_t = bb31_t;
+ uint32_t val;
+ static const uint32_t DEGREE = 1;
+ static const uint32_t NBITS = 31;
+ static const uint32_t MOD = 0x78000001;
+
+ inline bb31_t() {}
+
+ inline bb31_t(uint32_t a) : val(a) {}
+
+ inline constexpr bb31_t(int a) : val(((uint64_t)a << 32) % MOD) {}
+
+ static inline const bb31_t zero() { return bb31_t(0); }
+
+ static inline const bb31_t one() { return bb31_t(ONE); }
+
+ static inline const bb31_t two() { return bb31_t(to_monty(2)); }
+
+ static inline uint32_t to_monty(uint32_t x) {
+ return (((uint64_t)x << MONTY_BITS) % MOD);
+ }
+
+ static inline uint32_t from_monty(uint32_t x) {
+ return monty_reduce((uint64_t)x);
+ }
+
+ static inline uint32_t monty_reduce(uint64_t x) {
+ uint64_t t = (x * (uint64_t)MONTY_MU) & (uint64_t)MONTY_MASK;
+ uint64_t u = t * (uint64_t)MOD;
+ uint64_t x_sub_u = x - u;
+ bool over = x < u;
+ uint32_t x_sub_u_hi = (uint32_t)(x_sub_u >> MONTY_BITS);
+ uint32_t corr = over ? MOD : 0;
+ return x_sub_u_hi + corr;
+ }
+
+ static inline bb31_t from_canonical_u32(uint32_t x) {
+ assert(x < MOD);
+ return bb31_t(to_monty(x));
+ }
+
+ static inline bb31_t from_canonical_u16(uint16_t x) {
+ return from_canonical_u32((uint32_t)x);
+ }
+
+ static inline bb31_t from_canonical_u8(uint8_t x) {
+ return from_canonical_u32((uint32_t)x);
+ }
+
+ static inline bb31_t from_bool(bool x) { return bb31_t(x * one().val); }
+
+ inline uint32_t as_canonical_u32() const { return from_monty(val); }
+
+ inline bb31_t& operator+=(bb31_t b) {
+ val += b.val;
+ if (val >= MOD)
+ val -= MOD;
+ return *this;
+ }
+
+ inline bb31_t& operator-=(bb31_t b) {
+ if (val < b.val)
+ val += MOD;
+ val -= b.val;
+ return *this;
+ }
+
+ inline bb31_t& operator*=(bb31_t b) {
+ uint64_t long_prod = (uint64_t)val * (uint64_t)b.val;
+ val = monty_reduce(long_prod);
+ return *this;
+ }
+
+ inline bb31_t square() { return *this * *this; }
+
+ friend bb31_t operator+(bb31_t a, bb31_t b) { return a += b; }
+
+ friend bb31_t operator-(bb31_t a, bb31_t b) { return a -= b; }
+
+ friend bb31_t operator*(bb31_t a, bb31_t b) { return a *= b; }
+
+ inline bb31_t& operator<<=(uint32_t l) {
+ while (l--) {
+ val <<= 1;
+ if (val >= MOD)
+ val -= MOD;
+ }
+
+ return *this;
+ }
+
+ friend inline bb31_t operator<<(bb31_t a, uint32_t l) { return a <<= l; }
+
+ inline bb31_t& operator>>=(uint32_t r) {
+ while (r--) {
+ val += val & 1 ? MOD : 0;
+ val >>= 1;
+ }
+
+ return *this;
+ }
+
+ inline bb31_t exp_power_of_2(uint32_t power_log) const {
+ bb31_t result = *this;
+ for (uint32_t i = 0; i < power_log; ++i) {
+ result = result.square();
+ }
+ return result;
+ }
+
+ inline bb31_t reciprocal() const {
+ assert(*this != zero());
+
+ bb31_t p1 = *this;
+ bb31_t p100000000 = p1.exp_power_of_2(8);
+ bb31_t p100000001 = p100000000 * p1;
+ bb31_t p10000000000000000 = p100000000.exp_power_of_2(8);
+ bb31_t p10000000100000001 = p10000000000000000 * p100000001;
+ bb31_t p10000000100000001000 = p10000000100000001.exp_power_of_2(3);
+ bb31_t p1000000010000000100000000 = p10000000100000001000.exp_power_of_2(5);
+ bb31_t p1000000010000000100000001 = p1000000010000000100000000 * p1;
+ bb31_t p1000010010000100100001001 =
+ p1000000010000000100000001 * p10000000100000001000;
+ bb31_t p10000000100000001000000010 = p1000000010000000100000001.square();
+ bb31_t p11000010110000101100001011 =
+ p10000000100000001000000010 * p1000010010000100100001001;
+ bb31_t p100000001000000010000000100 = p10000000100000001000000010.square();
+ bb31_t p111000011110000111100001111 =
+ p100000001000000010000000100 * p11000010110000101100001011;
+ bb31_t p1110000111100001111000011110000 =
+ p111000011110000111100001111.exp_power_of_2(4);
+ bb31_t p1110111111111111111111111111111 =
+ p1110000111100001111000011110000 * p111000011110000111100001111;
+
+ return p1110111111111111111111111111111;
+ }
+
+ inline bool operator==(const bb31_t rhs) const { return val == rhs.val; }
+
+ inline bb31_t &operator^=(int b) {
+ bb31_t sqr = *this;
+ if ((b & 1) == 0)
+ *this = one();
+ while (b >>= 1) {
+ sqr = sqr.square();
+ if (b & 1)
+ *this *= sqr;
+ }
+ return *this;
+ }
+
+ friend bb31_t operator^(bb31_t a, uint32_t b) { return a ^= b; }
+
+ inline bb31_t& sqr() { return *this; }
+
+ inline void set_to_zero() { val = 0; }
+
+ inline bool is_zero() const { return val == 0; }
+};
+
+#endif // __CUDA__ARCH__
\ No newline at end of file
diff --git a/crates/core/machine/include/bitwise.hpp b/crates/core/machine/include/bitwise.hpp
new file mode 100644
index 0000000000..190e5f287c
--- /dev/null
+++ b/crates/core/machine/include/bitwise.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::bitwise {
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, BitwiseCols& cols) {
+ cols.shard = F::from_canonical_u32(event.shard);
+ write_word_from_u32(cols.a, event.a);
+ write_word_from_u32(cols.b, event.b);
+ write_word_from_u32(cols.c, event.c);
+ cols.is_xor = F::from_bool(event.opcode == Opcode::XOR);
+ cols.is_or = F::from_bool(event.opcode == Opcode::OR);
+ cols.is_and = F::from_bool(event.opcode == Opcode::AND);
+
+ // No byte lookup yet.
+}
+} // namespace sp1::bitwise
diff --git a/crates/core/machine/include/cpu.hpp b/crates/core/machine/include/cpu.hpp
new file mode 100644
index 0000000000..41f78f9ef6
--- /dev/null
+++ b/crates/core/machine/include/cpu.hpp
@@ -0,0 +1,555 @@
+#pragma once
+
+#include
+#include
+
+#include "memory.hpp"
+#include "prelude.hpp"
+#include "utils.hpp"
+
+// namespace sp1_core_machine_sys::cpu {
+
+// template
+// __SP1_HOSTDEV__ void populate_shard_clk(const CpuEventFfi& event, CpuCols& cols) {
+// // cols.shard = F::from_canonical_u32(event.shard).val;
+// // cols.clk = F::from_canonical_u32(event.clk).val;
+
+// // const uint16_t clk_16bit_limb = (uint16_t)event.clk;
+// // const uint8_t clk_8bit_limb = (uint8_t)(event.clk >> 16);
+// // cols.clk_16bit_limb = F::from_canonical_u16(clk_16bit_limb).val;
+// // cols.clk_8bit_limb = F::from_canonical_u8(clk_8bit_limb).val;
+
+// // blu_events.add_byte_lookup_event(ByteLookupEvent::new(
+// // event.shard,
+// // U16Range,
+// // event.shard as u16,
+// // 0,
+// // 0,
+// // 0,
+// // ));
+// // blu_events.add_byte_lookup_event(ByteLookupEvent::new(
+// // event.shard,
+// // U16Range,
+// // clk_16bit_limb,
+// // 0,
+// // 0,
+// // 0,
+// // ));
+// // blu_events.add_byte_lookup_event(ByteLookupEvent::new(
+// // event.shard,
+// // ByteOpcode::U8Range,
+// // 0,
+// // 0,
+// // 0,
+// // clk_8bit_limb as u8,
+// // ));
+// }
+
+// // template
+// // __SP1_HOSTDEV__ void
+// // instruction_populate(InstructionCols& self, const Instruction& instruction) {
+// // self.opcode = F::from_canonical_u32((uint32_t)instruction.opcode).val;
+// // write_word_from_u32(self.op_a, instruction.op_a);
+// // write_word_from_u32(self.op_b, instruction.op_b);
+// // write_word_from_u32(self.op_c, instruction.op_c);
+
+// // self.op_a_0 = F::from_bool(instruction.op_a == 0).val; // 0 = Register::X0
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void
+// // selectors_populate(OpcodeSelectorCols& self, const Instruction& instruction) {
+// // self.imm_b = F::from_bool(instruction.imm_b).val;
+// // self.imm_c = F::from_bool(instruction.imm_c).val;
+
+// // switch (instruction.opcode) {
+// // // Corresponds to `instruction.is_alu_instruction()` in Rust.
+// // case Opcode::ADD:
+// // case Opcode::SUB:
+// // case Opcode::XOR:
+// // case Opcode::OR:
+// // case Opcode::AND:
+// // case Opcode::SLL:
+// // case Opcode::SRL:
+// // case Opcode::SRA:
+// // case Opcode::SLT:
+// // case Opcode::SLTU:
+// // case Opcode::MUL:
+// // case Opcode::MULH:
+// // case Opcode::MULHU:
+// // case Opcode::MULHSU:
+// // case Opcode::DIV:
+// // case Opcode::DIVU:
+// // case Opcode::REM:
+// // case Opcode::REMU:
+// // self.is_alu = F::one().val;
+// // break;
+// // // Corresponds to `instruction.is_ecall_instruction()` in Rust.
+// // case Opcode::ECALL:
+// // self.is_ecall = F::one().val;
+// // break;
+// // // Cleaner version of the `instruction.is_memory_instruction()` branch from Rust.
+// // case Opcode::LB:
+// // self.is_lb = F::one().val;
+// // break;
+// // case Opcode::LBU:
+// // self.is_lbu = F::one().val;
+// // break;
+// // case Opcode::LHU:
+// // self.is_lhu = F::one().val;
+// // break;
+// // case Opcode::LH:
+// // self.is_lh = F::one().val;
+// // break;
+// // case Opcode::LW:
+// // self.is_lw = F::one().val;
+// // break;
+// // case Opcode::SB:
+// // self.is_sb = F::one().val;
+// // break;
+// // case Opcode::SH:
+// // self.is_sh = F::one().val;
+// // break;
+// // case Opcode::SW:
+// // self.is_sw = F::one().val;
+// // break;
+// // // Cleaner version of the `instruction.is_branch_instruction()` branch from Rust.
+// // case Opcode::BEQ:
+// // self.is_beq = F::one().val;
+// // break;
+// // case Opcode::BNE:
+// // self.is_bne = F::one().val;
+// // break;
+// // case Opcode::BLT:
+// // self.is_blt = F::one().val;
+// // break;
+// // case Opcode::BGE:
+// // self.is_bge = F::one().val;
+// // break;
+// // case Opcode::BLTU:
+// // self.is_bltu = F::one().val;
+// // break;
+// // case Opcode::BGEU:
+// // self.is_bgeu = F::one().val;
+// // break;
+// // // Opcodes which each have their own branch in the original Rust function.
+// // case Opcode::JAL:
+// // self.is_jal = F::one().val;
+// // break;
+// // case Opcode::JALR:
+// // self.is_jalr = F::one().val;
+// // break;
+// // case Opcode::AUIPC:
+// // self.is_auipc = F::one().val;
+// // break;
+// // case Opcode::UNIMP:
+// // self.is_unimpl = F::one().val;
+// // break;
+// // default:
+// // break;
+// // }
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void
+// // babybear_word_populate(BabyBearWordRangeChecker& self, uint32_t value) {
+// // for (uintptr_t i = 0; i < BYTE_SIZE; ++i) {
+// // self.most_sig_byte_decomp[i] = F::from_bool((value & (1 << (i + 24))) != 0).val;
+// // }
+// // self.and_most_sig_byte_decomp_3_to_5 =
+// // F::from_bool(self.most_sig_byte_decomp[3] != 0 && self.most_sig_byte_decomp[4] != 0).val;
+// // self.and_most_sig_byte_decomp_3_to_6 =
+// // F::from_bool(self.and_most_sig_byte_decomp_3_to_5 != 0 && self.most_sig_byte_decomp[5] != 0)
+// // .val;
+// // self.and_most_sig_byte_decomp_3_to_7 =
+// // F::from_bool(self.and_most_sig_byte_decomp_3_to_6 != 0 && self.most_sig_byte_decomp[6] != 0)
+// // .val;
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void populate_memory(CpuCols& cols, const CpuEventFfi& event) {
+// // // Populate addr_word and addr_aligned columns.
+// // MemoryColumns& memory_columns = cols.opcode_specific_columns.memory;
+// // // Wraps because the types involved are unsigned integers.
+// // const uint32_t memory_addr = event.b + event.c;
+// // const uint32_t aligned_addr = memory_addr - (memory_addr % (uint32_t)WORD_SIZE);
+// // write_word_from_u32(memory_columns.addr_word, memory_addr);
+// // babybear_word_populate(memory_columns.addr_word_range_checker, memory_addr);
+// // memory_columns.addr_aligned = F::from_canonical_u32(aligned_addr).val;
+
+// // // Populate the aa_least_sig_byte_decomp columns.
+// // // assert(aligned_addr % 4 == 0);
+// // const uint8_t aligned_addr_ls_byte = (uint8_t)aligned_addr;
+// // for (uintptr_t i = 0; i < 6; ++i) {
+// // memory_columns.aa_least_sig_byte_decomp[i] =
+// // F::from_bool((aligned_addr_ls_byte & (1 << (i + 2))) != 0).val;
+// // }
+// // memory_columns.addr_word_nonce = F::from_canonical_u32(event.memory_add_nonce).val;
+
+// // // // Populate memory offsets.
+// // const uint8_t addr_offset = (uint8_t)(memory_addr % (uint32_t)WORD_SIZE);
+// // memory_columns.addr_offset = F::from_canonical_u8(addr_offset).val;
+// // memory_columns.offset_is_one = F::from_bool(addr_offset == 1).val;
+// // memory_columns.offset_is_two = F::from_bool(addr_offset == 2).val;
+// // memory_columns.offset_is_three = F::from_bool(addr_offset == 3).val;
+
+// // // If it is a load instruction, set the unsigned_mem_val column.
+// // const uint32_t mem_value = memory::unwrap_value(event.memory_record);
+
+// // // // Add event to byte lookup for byte range checking each byte in the memory addr
+// // // let addr_bytes = memory_addr.to_le_bytes();
+// // // for byte_pair in addr_bytes.chunks_exact(2) {
+// // // blu_events.add_byte_lookup_event(ByteLookupEvent {
+// // // shard: event.shard,
+// // // opcode: ByteOpcode::U8Range,
+// // // a1: 0,
+// // // a2: 0,
+// // // b: byte_pair[0],
+// // // c: byte_pair[1],
+// // // });
+// // // }
+
+// // uint32_t unsigned_mem_val = mem_value;
+// // switch (event.instruction.opcode) {
+// // case Opcode::LB:
+// // case Opcode::LBU:
+// // unsigned_mem_val = (uint32_t)(uint8_t)(mem_value >> 8 * addr_offset);
+// // break;
+// // case Opcode::LH:
+// // case Opcode::LHU:
+// // unsigned_mem_val = ((addr_offset >> 1) & 0x1) == 0 ? (mem_value & 0x0000FFFF)
+// // : (mem_value & 0xFFFF0000) >> 16;
+// // break;
+// // case Opcode::LW:
+// // // The value assigned at declaration is correct.
+// // break;
+// // default:
+// // return;
+// // }
+// // // Guard above ensures instruction is a load.
+// // write_word_from_u32(cols.unsigned_mem_val, unsigned_mem_val);
+
+// // uint8_t most_sig_mem_value_byte;
+// // switch (event.instruction.opcode) {
+// // case Opcode::LB:
+
+// // most_sig_mem_value_byte = (uint8_t)unsigned_mem_val;
+// // break;
+// // case Opcode::LH:
+// // most_sig_mem_value_byte = (uint8_t)(unsigned_mem_val >> 8);
+// // break;
+// // default:
+// // // The load instruction is unsigned.
+// // // Set the `mem_value_is_pos_not_x0` composite flag.
+// // cols.mem_value_is_pos_not_x0 =
+// // F::from_bool(event.instruction.op_a != 0).val; // 0 = Register::X0
+// // return;
+// // }
+// // // Guard above ensures the load instruction is signed.
+// // for (intptr_t i = BYTE_SIZE - 1; i >= 0; --i) {
+// // memory_columns.most_sig_byte_decomp[i] =
+// // F::from_canonical_u32(most_sig_mem_value_byte >> i & 0x1).val;
+// // }
+// // bool mem_value_is_pos_not_x0 = memory_columns.most_sig_byte_decomp[7] == F::zero().val;
+// // if (!mem_value_is_pos_not_x0) {
+// // cols.mem_value_is_neg_not_x0 =
+// // F::from_bool(event.instruction.op_a != 0).val; // 0 = Register::X0
+// // cols.unsigned_mem_val_nonce = F::from_canonical_u32(event.memory_sub_nonce).val;
+// // }
+// // // Set the `mem_value_is_pos_not_x0` composite flag.
+// // cols.mem_value_is_pos_not_x0 = F::from_bool(mem_value_is_pos_not_x0).val;
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void populate_branch(CpuCols& cols, const CpuEventFfi& event) {
+// // // let branch_columns = cols.opcode_specific_columns.branch_mut();
+// // BranchCols& branch_columns = cols.opcode_specific_columns.branch;
+
+// // Opcode opcode = event.instruction.opcode;
+// // const bool use_signed_comparison = opcode == Opcode::BLT || opcode == Opcode::BGE;
+
+// // const bool a_eq_b = event.a == event.b;
+// // const bool a_lt_b =
+// // use_signed_comparison ? ((int32_t)event.a < (int32_t)event.b) : (event.a < event.b);
+// // const bool a_gt_b =
+// // use_signed_comparison ? ((int32_t)event.a > (int32_t)event.b) : (event.a > event.b);
+
+// // branch_columns.a_lt_b_nonce = F::from_canonical_u32(event.branch_lt_nonce).val;
+// // branch_columns.a_gt_b_nonce = F::from_canonical_u32(event.branch_gt_nonce).val;
+
+// // branch_columns.a_eq_b = F::from_bool(a_eq_b).val;
+// // branch_columns.a_lt_b = F::from_bool(a_lt_b).val;
+// // branch_columns.a_gt_b = F::from_bool(a_gt_b).val;
+
+// // bool branching;
+// // switch (opcode) {
+// // case Opcode::BEQ:
+// // branching = a_eq_b;
+// // break;
+// // case Opcode::BNE:
+// // branching = !a_eq_b;
+// // break;
+// // case Opcode::BLT:
+// // case Opcode::BLTU:
+// // branching = a_lt_b;
+// // break;
+// // case Opcode::BGE:
+// // case Opcode::BGEU:
+// // branching = a_eq_b || a_gt_b;
+// // break;
+// // default:
+// // // Precondition violated.
+// // assert(false);
+// // break;
+// // }
+
+// // // Unsigned arithmetic wraps.
+// // const uint32_t next_pc = event.pc + event.c;
+// // write_word_from_u32(branch_columns.pc, event.pc);
+// // write_word_from_u32(branch_columns.next_pc, next_pc);
+// // babybear_word_populate(branch_columns.pc_range_checker, event.pc);
+// // babybear_word_populate(branch_columns.next_pc_range_checker, next_pc);
+
+// // if (branching) {
+// // cols.branching = F::one().val;
+// // branch_columns.next_pc_nonce = F::from_canonical_u32(event.branch_add_nonce).val;
+// // } else {
+// // cols.not_branching = F::one().val;
+// // }
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void populate_jump(CpuCols& cols, const CpuEventFfi& event) {
+// // // let jump_columns = cols.opcode_specific_columns.jump_mut();
+// // JumpCols& jump_columns = cols.opcode_specific_columns.jump;
+
+// // switch (event.instruction.opcode) {
+// // case Opcode::JAL: {
+// // // Unsigned arithmetic wraps.
+// // uint32_t next_pc = event.pc + event.b;
+// // babybear_word_populate(jump_columns.op_a_range_checker, event.a);
+// // write_word_from_u32(jump_columns.pc, event.pc);
+// // babybear_word_populate(jump_columns.pc_range_checker, event.pc);
+// // write_word_from_u32(jump_columns.next_pc, next_pc);
+// // babybear_word_populate(jump_columns.next_pc_range_checker, next_pc);
+// // jump_columns.jal_nonce = F::from_canonical_u32(event.jump_jal_nonce).val;
+// // break;
+// // }
+// // case Opcode::JALR: {
+// // // Unsigned arithmetic wraps.
+// // uint32_t next_pc = event.b + event.c;
+// // babybear_word_populate(jump_columns.op_a_range_checker, event.a);
+// // write_word_from_u32(jump_columns.next_pc, next_pc);
+// // babybear_word_populate(jump_columns.next_pc_range_checker, next_pc);
+// // jump_columns.jalr_nonce = F::from_canonical_u32(event.jump_jalr_nonce).val;
+// // break;
+// // }
+// // default:
+// // // Precondition violated.
+// // assert(false);
+// // break;
+// // }
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void populate_auipc(CpuCols& cols, const CpuEventFfi& event) {
+// // AuipcCols& auipc_columns = cols.opcode_specific_columns.auipc;
+
+// // write_word_from_u32(auipc_columns.pc, event.pc);
+// // babybear_word_populate(auipc_columns.pc_range_checker, event.pc);
+// // auipc_columns.auipc_nonce = F::from_canonical_u32(event.auipc_nonce).val;
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ void
+// // is_zero_operation_populate_from_field_element(IsZeroOperation& self, F a) {
+// // if (a == F::zero()) {
+// // self.inverse = F::zero().val;
+// // self.result = F::one().val;
+// // } else {
+// // self.inverse = a.reciprocal().val;
+// // self.result = F::zero().val;
+// // }
+// // // F is_zero = F::one() - F(self.inverse) * a;
+// // // assert(is_zero == F(self.result));
+// // // let is_zero = one.clone() - cols.inverse * a.clone();
+// // // builder.when(is_real.clone()).assert_eq(is_zero, cols.result);
+
+// // // let prod = self.inverse * a;
+// // // debug_assert!(prod == F::one() || prod == F::zero());
+// // // (a == F::zero()) as u32
+// // }
+
+// // template
+// // __SP1_HOSTDEV__ bool populate_ecall(CpuCols& cols, const CpuEventFfi& event) {
+// // bool is_halt = false;
+
+// // // The send_to_table column is the 1st entry of the op_a_access column prev_value field.
+// // // Look at `ecall_eval` in cpu/air/mod.rs for the corresponding constraint and
+// // // explanation.
+// // EcallCols& ecall_cols = cols.opcode_specific_columns.ecall;
+
+// // cols.ecall_mul_send_to_table = cols.op_a_access.prev_value._0[1];
+
+// // F syscall_id = F(cols.op_a_access.prev_value._0[0]);
+
+// // // In the following statements, truncating to `uint8_t` is the equivalent of the
+// // // `SyscallCode::get_syscall_id` calls from the Rust code.
+
+// // // Populate `is_enter_unconstrained`.
+// // is_zero_operation_populate_from_field_element(
+// // ecall_cols.is_enter_unconstrained,
+// // syscall_id - F::from_canonical_u8((uint8_t)SyscallCode::ENTER_UNCONSTRAINED)
+// // );
+
+// // // Populate `is_hint_len`.
+// // is_zero_operation_populate_from_field_element(
+// // ecall_cols.is_hint_len,
+// // syscall_id - F::from_canonical_u8((uint8_t)SyscallCode::HINT_LEN)
+// // );
+
+// // // Populate `is_halt`.
+// // is_zero_operation_populate_from_field_element(
+// // ecall_cols.is_halt,
+// // syscall_id - F::from_canonical_u8((uint8_t)SyscallCode::HALT)
+// // );
+
+// // // Populate `is_commit`.
+// // is_zero_operation_populate_from_field_element(
+// // ecall_cols.is_commit,
+// // syscall_id - F::from_canonical_u8((uint8_t)SyscallCode::COMMIT)
+// // );
+
+// // // Populate `is_commit_deferred_proofs`.
+// // is_zero_operation_populate_from_field_element(
+// // ecall_cols.is_commit_deferred_proofs,
+// // syscall_id - F::from_canonical_u8((uint8_t)SyscallCode::COMMIT_DEFERRED_PROOFS)
+// // );
+
+// // // If the syscall is `COMMIT` or `COMMIT_DEFERRED_PROOFS`, set the index bitmap and
+// // // digest word.
+// // if (syscall_id
+// // == F::from_canonical_u8((uint8_t)SyscallCode::COMMIT
+// // ) // Comment to make my editor format nicely...
+// // || syscall_id == F::from_canonical_u8((uint8_t)SyscallCode::COMMIT_DEFERRED_PROOFS)) {
+// // uint32_t digest_idx = word_to_u32(cols.op_b_access.access.value);
+// // ecall_cols.index_bitmap[digest_idx] = F::one().val;
+// // }
+
+// // // Write the syscall nonce.
+// // ecall_cols.syscall_nonce = F::from_canonical_u32(event.syscall_nonce).val;
+
+// // is_halt = syscall_id == F::from_canonical_u32((uint8_t)SyscallCode::HALT);
+
+// // // For halt and commit deferred proofs syscalls, we need to baby bear range check one of
+// // // it's operands.
+// // if (is_halt) {
+// // write_word_from_u32(ecall_cols.operand_to_check, event.b);
+// // babybear_word_populate(ecall_cols.operand_range_check_cols, event.b);
+// // cols.ecall_range_check_operand = F::one().val;
+// // }
+
+// // if (syscall_id == F::from_canonical_u32((uint8_t)SyscallCode::COMMIT_DEFERRED_PROOFS)) {
+// // write_word_from_u32(ecall_cols.operand_to_check, event.c);
+// // babybear_word_populate(ecall_cols.operand_range_check_cols, event.c);
+// // cols.ecall_range_check_operand = F::one().val;
+// // }
+
+// // return is_halt;
+// // }
+
+// template
+// __SP1_HOSTDEV__ void event_to_row(const CpuEventFfi& event, CpuCols& cols) {
+// // // Populate shard and clk columns.
+// // populate_shard_clk(event, cols);
+
+// // // Populate the nonce.
+// // cols.nonce = F::from_canonical_u32(event.alu_nonce).val;
+
+// // // Populate basic fields.
+// // cols.pc = F::from_canonical_u32(event.pc).val;
+// // cols.next_pc = F::from_canonical_u32(event.next_pc).val;
+// // instruction_populate(cols.instruction, event.instruction);
+// // // cols.instruction.populate(event.instruction);
+// // selectors_populate(cols.selectors, event.instruction);
+// // // cols.selectors.populate(event.instruction);
+// // write_word_from_u32(cols.op_a_access.access.value, event.a);
+// // write_word_from_u32(cols.op_b_access.access.value, event.b);
+// // write_word_from_u32(cols.op_c_access.access.value, event.c);
+
+// // // // Populate memory accesses for a, b, and c.
+// // // The function guards against the record being `None`.
+// // memory::populate_read_write(cols.op_a_access, event.a_record);
+// // if (event.b_record.tag == OptionMemoryRecordEnum::Tag::Read) {
+// // memory::populate_read(cols.op_b_access, event.b_record.read._0);
+// // }
+// // if (event.c_record.tag == OptionMemoryRecordEnum::Tag::Read) {
+// // memory::populate_read(cols.op_c_access, event.c_record.read._0);
+// // }
+
+// // // // Populate range checks for a.
+// // // let a_bytes = cols
+// // // .op_a_access
+// // // .access
+// // // .val
+// // // .0
+// // // .iter()
+// // // .map(|x| x.as_canonical_u32())
+// // // .collect::>();
+// // // blu_events.add_byte_lookup_event(ByteLookupEvent {
+// // // shard: event.shard,
+// // // opcode: ByteOpcode::U8Range,
+// // // a1: 0,
+// // // a2: 0,
+// // // b: a_bytes[0] as u8,
+// // // c: a_bytes[1] as u8,
+// // // });
+// // // blu_events.add_byte_lookup_event(ByteLookupEvent {
+// // // shard: event.shard,
+// // // opcode: ByteOpcode::U8Range,
+// // // a1: 0,
+// // // a2: 0,
+// // // b: a_bytes[2] as u8,
+// // // c: a_bytes[3] as u8,
+// // // });
+
+// // // Populate memory accesses for reading from memory.
+// // // `event.memory` appears to be vestigial.
+// // // assert_eq!(event.memory_record.is_some(), event.memory.is_some());
+// // // The function guards against the record being `None`.
+// // memory::populate_read_write(
+// // cols.opcode_specific_columns.memory.memory_access,
+// // event.memory_record
+// // );
+
+// // // Populate memory, branch, jump, and auipc specific fields.
+// // const bool is_memory = opcode_utils::is_memory(event.instruction.opcode);
+// // const bool is_branch = opcode_utils::is_branch(event.instruction.opcode);
+// // const bool is_jump = opcode_utils::is_jump(event.instruction.opcode);
+// // const bool is_auipc = event.instruction.opcode == Opcode::AUIPC;
+// // const bool is_ecall = event.instruction.opcode == Opcode::ECALL;
+// // // Calculated by `populate_ecall`, if called.
+// // bool is_halt = false;
+// // // Unlike the Rust code, we guard outside the function bodies so we can reuse the booleans.
+// // if (is_memory) {
+// // populate_memory(cols, event);
+// // }
+// // if (is_branch) {
+// // populate_branch(cols, event);
+// // }
+// // if (is_jump) {
+// // populate_jump(cols, event);
+// // }
+// // if (is_auipc) {
+// // populate_auipc(cols, event);
+// // }
+// // if (is_ecall) {
+// // is_halt = populate_ecall(cols, event);
+// // }
+
+// // cols.is_sequential_instr = F::from_bool(!(is_branch || is_jump || is_halt)).val;
+
+// // // Assert that the instruction is not a no-op.
+// // cols.is_real = F::one().val;
+// }
+// } // namespace sp1::cpu
\ No newline at end of file
diff --git a/crates/core/machine/include/lt.hpp b/crates/core/machine/include/lt.hpp
new file mode 100644
index 0000000000..3c83c144f4
--- /dev/null
+++ b/crates/core/machine/include/lt.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#include
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::lt {
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, LtCols& cols) {
+ array_t a = u32_to_le_bytes(event.a);
+ array_t b = u32_to_le_bytes(event.b);
+ array_t c = u32_to_le_bytes(event.c);
+ cols.shard = F::from_canonical_u32(event.shard).val;
+ word_from_le_bytes(cols.a, a);
+ word_from_le_bytes(cols.b, b);
+ word_from_le_bytes(cols.c, c);
+
+ // If this is SLT, mask the MSB of b & c before computing cols.bits.
+ uint8_t masked_b = b[3] & 0x7f;
+ uint8_t masked_c = c[3] & 0x7f;
+ cols.b_masked = F::from_canonical_u8(masked_b);
+ cols.c_masked = F::from_canonical_u8(masked_c);
+
+ // // Send the masked interaction.
+ // blu.add_byte_lookup_event(ByteLookupEvent {
+ // shard: event.shard,
+ // channel: event.channel,
+ // opcode: ByteOpcode::AND,
+ // a1: masked_b as u16,
+ // a2: 0,
+ // b: b[3],
+ // c: 0x7f,
+ // });
+ // blu.add_byte_lookup_event(ByteLookupEvent {
+ // shard: event.shard,
+ // channel: event.channel,
+ // opcode: ByteOpcode::AND,
+ // a1: masked_c as u16,
+ // a2: 0,
+ // b: c[3],
+ // c: 0x7f,
+ // });
+
+ array_t b_comp = b;
+ array_t c_comp = c;
+ if (event.opcode == Opcode::SLT) {
+ b_comp[3] = masked_b;
+ c_comp[3] = masked_c;
+ }
+
+ // Set the byte equality flags.
+ intptr_t i = 3;
+ while (true) {
+ uint8_t b_byte = b_comp[i];
+ uint8_t c_byte = c_comp[i];
+ if (b_byte != c_byte) {
+ cols.byte_flags[i] = F::one();
+ cols.sltu = F::from_bool(b_byte < c_byte);
+ F b_byte_f = F::from_canonical_u8(b_byte);
+ F c_byte_f = F::from_canonical_u8(c_byte);
+ cols.not_eq_inv = (b_byte_f - c_byte_f).reciprocal();
+ cols.comparison_bytes[0] = b_byte_f;
+ cols.comparison_bytes[1] = c_byte_f;
+ break;
+ }
+ if (i == 0) {
+ // The equality `b_comp == c_comp` holds.
+ cols.is_comp_eq = F::one();
+ break;
+ }
+ --i;
+ }
+
+ cols.msb_b = F::from_bool((b[3] >> 7) & 1);
+ cols.msb_c = F::from_bool((c[3] >> 7) & 1);
+ cols.is_sign_eq = F::from_bool(event.opcode != Opcode::SLT || cols.msb_b == cols.msb_c);
+
+ cols.is_slt = F::from_bool(event.opcode == Opcode::SLT);
+ cols.is_sltu = F::from_bool(event.opcode == Opcode::SLTU);
+
+ cols.bit_b = (F(cols.msb_b) * F(cols.is_slt));
+ cols.bit_c = (F(cols.msb_c) * F(cols.is_slt));
+
+ // if (F(cols.a._0[0]) != F(cols.bit_b) * (F::one() - F(cols.bit_c)) + F(cols.is_sign_eq) * F(cols.sltu))
+ // {
+ // std::exit(1);
+ // }
+
+ // blu.add_byte_lookup_event(ByteLookupEvent {
+ // shard: event.shard,
+ // channel: event.channel,
+ // opcode: ByteOpcode::LTU,
+ // a1: cols.sltu.as_canonical_u32() as u16,
+ // a2: 0,
+ // b: cols.comparison_bytes[0].as_canonical_u32() as u8,
+ // c: cols.comparison_bytes[1].as_canonical_u32() as u8,
+ // });
+}
+} // namespace sp1::lt
\ No newline at end of file
diff --git a/crates/core/machine/include/memory.hpp b/crates/core/machine/include/memory.hpp
new file mode 100644
index 0000000000..216a3a449d
--- /dev/null
+++ b/crates/core/machine/include/memory.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+// namespace sp1_core_machine_sys::memory {
+// __SP1_HOSTDEV__ __SP1_INLINE__ uint32_t unwrap_value(const OptionMemoryRecordEnum& record) {
+// switch (record.tag) {
+// case OptionMemoryRecordEnum::Tag::Read:
+// return record.read._0.value;
+// case OptionMemoryRecordEnum::Tag::Write:
+// return record.write._0.value;
+// default:
+// // Either the tag is `None` or it is an invalid value.
+// assert(false);
+// }
+// // Unreachable.
+// return 0;
+// }
+
+// template
+// __SP1_HOSTDEV__ void populate_access(
+// MemoryAccessCols& self,
+// const MemoryRecord& current_record,
+// const MemoryRecord& prev_record
+// ) {
+// write_word_from_u32(self.value, current_record.value);
+
+// self.prev_shard = F::from_canonical_u32(prev_record.shard).val;
+// self.prev_clk = F::from_canonical_u32(prev_record.timestamp).val;
+
+// // Fill columns used for verifying current memory access time value is greater than
+// // previous's.
+// const bool use_clk_comparison = prev_record.shard == current_record.shard;
+// self.compare_clk = F::from_bool(use_clk_comparison).val;
+// const uint32_t prev_time_value = use_clk_comparison ? prev_record.timestamp : prev_record.shard;
+// const uint32_t current_time_value =
+// use_clk_comparison ? current_record.timestamp : current_record.shard;
+
+// const uint32_t diff_minus_one = current_time_value - prev_time_value - 1;
+// const uint16_t diff_16bit_limb = (uint16_t)(diff_minus_one);
+// self.diff_16bit_limb = F::from_canonical_u16(diff_16bit_limb).val;
+// const uint8_t diff_8bit_limb = (uint8_t)(diff_minus_one >> 16);
+// self.diff_8bit_limb = F::from_canonical_u8(diff_8bit_limb).val;
+
+// // let shard = current_record.shard;
+
+// // // Add a byte table lookup with the 16Range op.
+// // output.add_u16_range_check(shard, diff_16bit_limb);
+
+// // // Add a byte table lookup with the U8Range op.
+// // output.add_u8_range_check(shard, 0, diff_8bit_limb as u8);
+// }
+
+// template
+// __SP1_HOSTDEV__ void
+// populate_read(MemoryReadCols& self, const MemoryReadRecord& record) {
+// const MemoryRecord current_record = {
+// .shard = record.shard,
+// .timestamp = record.timestamp,
+// .value = record.value,
+// };
+// const MemoryRecord prev_record = {
+// .shard = record.prev_shard,
+// .timestamp = record.prev_timestamp,
+// .value = record.value,
+// };
+// populate_access(self.access, current_record, prev_record);
+// }
+
+// template
+// __SP1_HOSTDEV__ void populate_read_write(
+// MemoryReadWriteCols& self,
+// const OptionMemoryRecordEnum& record
+// ) {
+// if (record.tag == OptionMemoryRecordEnum::Tag::None) {
+// return;
+// }
+// MemoryRecord current_record;
+// MemoryRecord prev_record;
+// switch (record.tag) {
+// case OptionMemoryRecordEnum::Tag::Read:
+// current_record = {
+// .shard = record.read._0.shard,
+// .timestamp = record.read._0.timestamp,
+// .value = record.read._0.value,
+// };
+// prev_record = {
+// .shard = record.read._0.prev_shard,
+// .timestamp = record.read._0.prev_timestamp,
+// .value = record.read._0.value,
+// };
+// break;
+// case OptionMemoryRecordEnum::Tag::Write:
+// current_record = {
+// .shard = record.write._0.shard,
+// .timestamp = record.write._0.timestamp,
+// .value = record.write._0.value,
+// };
+// prev_record = {
+// .shard = record.write._0.prev_shard,
+// .timestamp = record.write._0.prev_timestamp,
+// .value = record.write._0.prev_value,
+// };
+// break;
+// default:
+// // Unreachable. `None` case guarded above.
+// assert(false);
+// break;
+// }
+// write_word_from_u32(self.prev_value, prev_record.value);
+// populate_access(self.access, current_record, prev_record);
+// }
+// } // namespace sp1::memory
\ No newline at end of file
diff --git a/crates/core/machine/include/memory_global.hpp b/crates/core/machine/include/memory_global.hpp
new file mode 100644
index 0000000000..6859686a56
--- /dev/null
+++ b/crates/core/machine/include/memory_global.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+#include "bb31_septic_extension_t.hpp"
+#include "memory_local.hpp"
+
+namespace sp1_core_machine_sys::memory_global {
+ template
+ __SP1_HOSTDEV__ void event_to_row(const MemoryInitializeFinalizeEvent* event, const bool is_receive, MemoryInitCols* cols) {
+ MemoryRecord record;
+ if (is_receive) {
+ record.shard = event->shard;
+ record.timestamp = event->timestamp;
+ record.value = event->value;
+ } else {
+ record.shard = 0;
+ record.timestamp = 0;
+ record.value = event->value;
+ }
+ // We populate only the things in the first loop of generate_trace here. The second loop is handled in the kernel directly.
+ sp1_core_machine_sys::memory_local::populate_memory(&cols->global_interaction_cols, &record, event->addr, is_receive);
+ cols->addr = F::from_canonical_u32(event->addr);
+ for(uintptr_t i = 0 ; i < 32 ; i++) {
+ cols->addr_bits.bits[i] = F::from_canonical_u32(((event->addr) >> i) & 1);
+ }
+ cols->addr_bits.and_most_sig_byte_decomp_3_to_5 = cols->addr_bits.bits[27] * cols->addr_bits.bits[28];
+ cols->addr_bits.and_most_sig_byte_decomp_3_to_6 = cols->addr_bits.and_most_sig_byte_decomp_3_to_5 * cols->addr_bits.bits[29];
+ cols->addr_bits.and_most_sig_byte_decomp_3_to_7 = cols->addr_bits.and_most_sig_byte_decomp_3_to_6 * cols->addr_bits.bits[30];
+ cols->shard = F::from_canonical_u32(event->shard);
+ cols->timestamp = F::from_canonical_u32(event->timestamp);
+ for(uintptr_t i = 0 ; i < 32 ; i++) {
+ cols->value[i] = F::from_canonical_u32(((event->value) >> i) & 1);
+ }
+ cols->is_real = F::from_canonical_u32(event->used);
+ }
+} // namespace sp1::memory_local
\ No newline at end of file
diff --git a/crates/core/machine/include/memory_local.hpp b/crates/core/machine/include/memory_local.hpp
new file mode 100644
index 0000000000..1d799208b2
--- /dev/null
+++ b/crates/core/machine/include/memory_local.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+#include "bb31_septic_extension_t.hpp"
+
+namespace sp1_core_machine_sys::memory_local {
+ template __SP1_HOSTDEV__ void populate_memory(GlobalInteractionOperation* cols, const MemoryRecord* record, const uint32_t& addr, bool is_receive) {
+ EF7 x_start;
+
+ {
+ x_start.value[0] = F::from_canonical_u32(record->shard + (1 << 24));
+ x_start.value[1] = F::from_canonical_u32(record->timestamp);
+ x_start.value[2] = F::from_canonical_u32(addr);
+ x_start.value[3] = F::from_canonical_u32(record->value & 255);
+ x_start.value[4] = F::from_canonical_u32((record->value >> 8) & 255);
+ x_start.value[5] = F::from_canonical_u32((record->value >> 16) & 255);
+ x_start.value[6] = F::from_canonical_u32((record->value >> 24) & 255);
+ }
+
+ #pragma unroll(1)
+ for(uint32_t offset = 0 ; offset < 256 ; offset++) {
+ EF7 x_trial = x_start.universal_hash();
+ EF7 y_sq = x_trial.curve_formula();
+ F y_sq_pow_r = y_sq.pow_r();
+ F is_square = y_sq_pow_r ^ 1006632960;
+ if(is_square == F::one()) {
+ EF7 y = y_sq.sqrt(y_sq_pow_r);
+ if (y.is_exception()) {
+ x_start += F::from_canonical_u32(1 << 16);
+ continue;
+ }
+ if (y.is_receive() != is_receive) {
+ y = EF7::zero() - y;
+ }
+ // x_trial, y
+ for(uint32_t idx = 0 ; idx < 8 ; idx++ ) {
+ cols->offset_bits[idx] = F::from_canonical_u32((offset >> idx) & 1);
+ }
+ for(uintptr_t i = 0 ; i < 7 ; i++) {
+ cols->x_coordinate._0[i] = x_trial.value[i];
+ cols->y_coordinate._0[i] = y.value[i];
+ }
+ uint32_t range_check_value;
+ if (is_receive) {
+ range_check_value = y.value[6].as_canonical_u32() - 1;
+ } else {
+ range_check_value = y.value[6].as_canonical_u32() - (F::MOD + 1) / 2;
+ }
+ F top_4_bits = F::zero();
+ for(uint32_t idx = 0 ; idx < 30 ; idx++) {
+ cols->y6_bit_decomp[idx] = F::from_canonical_u32((range_check_value >> idx) & 1);
+ if (idx >= 26) {
+ top_4_bits += cols->y6_bit_decomp[idx];
+ }
+ }
+ top_4_bits -= F::from_canonical_u32(4);
+ cols->range_check_witness = top_4_bits.reciprocal();
+ return;
+ }
+ x_start += F::from_canonical_u32(1 << 16);
+ }
+ assert(false);
+ }
+
+ template
+ __SP1_HOSTDEV__ void event_to_row(const MemoryLocalEvent* event, SingleMemoryLocal* cols) {
+ populate_memory(&cols->initial_global_interaction_cols, &event->initial_mem_access, event->addr, true);
+ populate_memory(&cols->final_global_interaction_cols, &event->final_mem_access, event->addr, false);
+ cols->addr = F::from_canonical_u32(event->addr);
+
+ cols->initial_shard = F::from_canonical_u32(event->initial_mem_access.shard);
+ cols->initial_clk = F::from_canonical_u32(event->initial_mem_access.timestamp);
+ write_word_from_u32_v2(cols->initial_value, event->initial_mem_access.value);
+
+ cols->final_shard = F::from_canonical_u32(event->final_mem_access.shard);
+ cols->final_clk = F::from_canonical_u32(event->final_mem_access.timestamp);
+ write_word_from_u32_v2(cols->final_value, event->final_mem_access.value);
+
+ cols->is_real = F::one();
+ }
+} // namespace sp1::memory_local
diff --git a/crates/core/machine/include/mul.hpp b/crates/core/machine/include/mul.hpp
new file mode 100644
index 0000000000..efa564275f
--- /dev/null
+++ b/crates/core/machine/include/mul.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::mul {
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, MulCols& cols) {
+ // // Ensure that the opcode is MUL, MULHU, MULH, or MULHSU.
+ // assert!(
+ // event.opcode == Opcode::MUL
+ // || event.opcode == Opcode::MULHU
+ // || event.opcode == Opcode::MULH
+ // || event.opcode == Opcode::MULHSU
+ // );
+
+ const array_t a = u32_to_le_bytes(event.a);
+ const array_t b = u32_to_le_bytes(event.b);
+ const array_t c = u32_to_le_bytes(event.c);
+
+ // Handle b and c's signs.
+ {
+ uint8_t b_msb = get_msb(b);
+ cols.b_msb = F::from_canonical_u8(b_msb).val;
+ uint8_t c_msb = get_msb(c);
+ cols.c_msb = F::from_canonical_u8(c_msb).val;
+
+ // If b is signed and it is negative, sign extend b.
+ if ((event.opcode == Opcode::MULH || event.opcode == Opcode::MULHSU) && b_msb == 1) {
+ cols.b_sign_extend = F::one().val;
+ }
+
+ // If c is signed and it is negative, sign extend c.
+ if (event.opcode == Opcode::MULH && c_msb == 1) {
+ cols.c_sign_extend = F::one().val;
+ }
+
+ // // Insert the MSB lookup events.
+ // {
+ // let words = [b_word, c_word];
+ // let mut blu_events: Vec = vec![];
+ // for word in words.iter() {
+ // let most_significant_byte = word[WORD_SIZE - 1];
+ // blu_events.push(ByteLookupEvent {
+ // shard: event.shard,
+ // opcode: ByteOpcode::MSB,
+ // a1: get_msb(*word) as u16,
+ // a2: 0,
+ // b: most_significant_byte,
+ // c: 0,
+ // });
+ // }
+ // record.add_byte_lookup_events(blu_events);
+ // }
+ }
+
+ // Required for the following logic to correctly multiply.
+ static_assert(2 * WORD_SIZE == LONG_WORD_SIZE);
+
+ array_t product {};
+ for (uintptr_t i = 0; i < WORD_SIZE; ++i) {
+ for (uintptr_t j = 0; j < WORD_SIZE; ++j) {
+ product[i + j] += (uint32_t)b[i] * (uint32_t)c[j];
+ }
+ if (cols.c_sign_extend != F::zero().val) {
+ for (uintptr_t j = WORD_SIZE; j < LONG_WORD_SIZE - i; ++j) {
+ product[i + j] += (uint32_t)b[i] * (uint32_t)0xFF;
+ }
+ }
+ }
+ if (cols.b_sign_extend != F::zero().val) {
+ for (uintptr_t i = WORD_SIZE; i < LONG_WORD_SIZE; ++i) {
+ for (uintptr_t j = 0; j < LONG_WORD_SIZE - i; ++j) {
+ product[i + j] += (uint32_t)0xFF * (uint32_t)c[j];
+ }
+ }
+ }
+
+ // Calculate the correct product using the `product` array. We store the
+ // correct carry value for verification.
+ const uint32_t base = 1 << BYTE_SIZE;
+ array_t carry {};
+ for (uintptr_t i = 0; i < LONG_WORD_SIZE; ++i) {
+ carry[i] = product[i] / base;
+ product[i] %= base;
+ if (i + 1 < LONG_WORD_SIZE) {
+ product[i + 1] += carry[i];
+ }
+ cols.carry[i] = F::from_canonical_u32(carry[i]).val;
+ }
+
+ for (uintptr_t i = 0; i < LONG_WORD_SIZE; ++i) {
+ cols.product[i] = F::from_canonical_u32(product[i]).val;
+ }
+ word_from_le_bytes(cols.a, a);
+ word_from_le_bytes(cols.b, b);
+ word_from_le_bytes(cols.c, c);
+ cols.is_real = F::one().val;
+ cols.is_mul = F::from_bool(event.opcode == Opcode::MUL).val;
+ cols.is_mulh = F::from_bool(event.opcode == Opcode::MULH).val;
+ cols.is_mulhu = F::from_bool(event.opcode == Opcode::MULHU).val;
+ cols.is_mulhsu = F::from_bool(event.opcode == Opcode::MULHSU).val;
+ cols.shard = F::from_canonical_u32(event.shard).val;
+
+ // // Range check.
+ // {
+ // record.add_u16_range_checks(event.shard, &carry.map(|x| x as u16));
+ // record.add_u8_range_checks(event.shard, &product.map(|x| x as u8));
+ // }
+}
+} // namespace sp1::mul
diff --git a/crates/core/machine/include/prelude.hpp b/crates/core/machine/include/prelude.hpp
new file mode 100644
index 0000000000..1f2b0db1e1
--- /dev/null
+++ b/crates/core/machine/include/prelude.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "sp1-core-machine-sys-cbindgen.hpp"
+
+#ifndef __CUDACC__
+ #define __SP1_HOSTDEV__
+ #define __SP1_INLINE__ inline
+ #include
+
+namespace sp1_core_machine_sys {
+template
+using array_t = std::array;
+} // namespace sp1
+#else
+ #define __SP1_HOSTDEV__ __host__ __device__
+ #define __SP1_INLINE__
+ #include
+
+namespace sp1_core_machine_sys {
+template
+using array_t = cuda::std::array;
+} // namespace sp1
+#endif
diff --git a/crates/core/machine/include/sll.hpp b/crates/core/machine/include/sll.hpp
new file mode 100644
index 0000000000..5f24a575a0
--- /dev/null
+++ b/crates/core/machine/include/sll.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+#include
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::sll {
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, ShiftLeftCols& cols) {
+ array_t a = u32_to_le_bytes(event.a);
+ array_t b = u32_to_le_bytes(event.b);
+ array_t c = u32_to_le_bytes(event.c);
+ cols.shard = F::from_canonical_u32(event.shard).val;
+ word_from_le_bytes(cols.a, a);
+ word_from_le_bytes(cols.b, b);
+ word_from_le_bytes(cols.c, c);
+ cols.is_real = F::one().val;
+ for (uintptr_t i = 0; i < BYTE_SIZE; ++i) {
+ cols.c_least_sig_byte[i] = F::from_canonical_u32((event.c >> i) & 1).val;
+ }
+
+ // Variables for bit shifting.
+ uintptr_t num_bits_to_shift = event.c % BYTE_SIZE;
+ for (uintptr_t i = 0; i < BYTE_SIZE; ++i) {
+ cols.shift_by_n_bits[i] = F::from_bool(num_bits_to_shift == i).val;
+ }
+
+ uint32_t bit_shift_multiplier = 1 << num_bits_to_shift;
+ cols.bit_shift_multiplier = F::from_canonical_u32(bit_shift_multiplier).val;
+
+ uint32_t carry = 0;
+ uint32_t base = 1 << BYTE_SIZE;
+
+ array_t bit_shift_result;
+ array_t bit_shift_result_carry;
+ for (uintptr_t i = 0; i < WORD_SIZE; ++i) {
+ uint32_t v = b[i] * bit_shift_multiplier + carry;
+ carry = v / base;
+ bit_shift_result[i] = (uint8_t)(v % base);
+ cols.bit_shift_result[i] = F::from_canonical_u8(bit_shift_result[i]).val;
+ bit_shift_result_carry[i] = (uint8_t)carry;
+ cols.bit_shift_result_carry[i] = F::from_canonical_u8(bit_shift_result_carry[i]).val;
+ }
+
+ // // Variables for byte shifting.
+ uintptr_t num_bytes_to_shift = (uintptr_t)(event.c & 0b11111) / BYTE_SIZE;
+ for (uintptr_t i = 0; i < WORD_SIZE; ++i) {
+ cols.shift_by_n_bytes[i] = F::from_bool(num_bytes_to_shift == i).val;
+ }
+
+ // // Range checks.
+ // {
+ // blu.add_u8_range_checks(event.shard, event.channel, &bit_shift_result);
+ // blu.add_u8_range_checks(event.shard, event.channel, &bit_shift_result_carry);
+ // }
+
+ // // Sanity check.
+ // for i in num_bytes_to_shift..WORD_SIZE {
+ // debug_assert_eq!(
+ // cols.bit_shift_result[i - num_bytes_to_shift],
+ // F::from_canonical_u8(a[i])
+ // );
+ // }
+}
+} // namespace sp1::sll
\ No newline at end of file
diff --git a/crates/core/machine/include/sr.hpp b/crates/core/machine/include/sr.hpp
new file mode 100644
index 0000000000..a5806fadb1
--- /dev/null
+++ b/crates/core/machine/include/sr.hpp
@@ -0,0 +1,106 @@
+#pragma once
+
+#include
+
+#include "prelude.hpp"
+#include "utils.hpp"
+
+namespace sp1_core_machine_sys::sr {
+template
+__SP1_HOSTDEV__ void event_to_row(const AluEvent& event, ShiftRightCols& cols) {
+ // Initialize cols with basic operands and flags derived from the current event.
+ {
+ cols.shard = F::from_canonical_u32(event.shard).val;
+ write_word_from_u32(cols.a, event.a);
+ write_word_from_u32(cols.b, event.b);
+ write_word_from_u32(cols.c, event.c);
+ cols.b_msb = F::from_canonical_u32((event.b >> 31) & 1).val;
+ cols.is_srl = F::from_bool(event.opcode == Opcode::SRL).val;
+ cols.is_sra = F::from_bool(event.opcode == Opcode::SRA).val;
+ cols.is_real = F::one().val;
+
+ for (uintptr_t i = 0; i < BYTE_SIZE; ++i) {
+ cols.c_least_sig_byte[i] = F::from_canonical_u32((event.c >> i) & 1).val;
+ }
+
+ // // Insert the MSB lookup event.
+ // let most_significant_byte = event.b.to_le_bytes()[WORD_SIZE - 1];
+ // blu.add_byte_lookup_events(vec![ByteLookupEvent {
+ // shard: event.shard,
+ // opcode: ByteOpcode::MSB,
+ // a1: ((most_significant_byte >> 7) & 1) as u16,
+ // a2: 0,
+ // b: most_significant_byte,
+ // c: 0,
+ // }]);
+ }
+
+ // Note that we take the least significant 5 bits per the RISC-V spec.
+ const uintptr_t num_bytes_to_shift = (event.c % 32) / BYTE_SIZE;
+ const uintptr_t num_bits_to_shift = (event.c % 32) % BYTE_SIZE;
+
+ // Byte shifting.
+ // Zero-initialize the array.
+ array_t byte_shift_result {};
+ {
+ for (uintptr_t i = 0; i < WORD_SIZE; ++i) {
+ cols.shift_by_n_bytes[i] = F::from_bool(num_bytes_to_shift == i).val;
+ }
+ // Sign extension is necessary only for arithmetic right shift.
+ array_t sign_extended_b = event.opcode == Opcode::SRA
+ ? u64_to_le_bytes((int64_t)(int32_t)event.b)
+ : u64_to_le_bytes((uint64_t)event.b);
+
+ for (uintptr_t i = 0; i < LONG_WORD_SIZE - num_bytes_to_shift; ++i) {
+ byte_shift_result[i] = sign_extended_b[i + num_bytes_to_shift];
+ cols.byte_shift_result[i] =
+ F::from_canonical_u8(sign_extended_b[i + num_bytes_to_shift]).val;
+ }
+ }
+
+ // Bit shifting.
+ {
+ for (uintptr_t i = 0; i < BYTE_SIZE; ++i) {
+ cols.shift_by_n_bits[i] = F::from_bool(num_bits_to_shift == i).val;
+ }
+ const uint32_t carry_multiplier = 1 << (8 - num_bits_to_shift);
+ uint32_t last_carry = 0;
+ array_t bit_shift_result;
+ array_t shr_carry_output_carry;
+ array_t shr_carry_output_shifted_byte;
+ for (intptr_t i = LONG_WORD_SIZE - 1; i >= 0; --i) {
+ auto [shift, carry] = shr_carry(byte_shift_result[i], num_bits_to_shift);
+
+ // let byte_event = ByteLookupEvent {
+ // shard: event.shard,
+ // opcode: ByteOpcode::ShrCarry,
+ // a1: shift as u16,
+ // a2: carry,
+ // b: byte_shift_result[i],
+ // c: num_bits_to_shift as u8,
+ // };
+ // blu.add_byte_lookup_event(byte_event);
+
+ shr_carry_output_carry[i] = carry;
+ cols.shr_carry_output_carry[i] = F::from_canonical_u8(carry).val;
+
+ shr_carry_output_shifted_byte[i] = shift;
+ cols.shr_carry_output_shifted_byte[i] = F::from_canonical_u8(shift).val;
+
+ uint8_t res = (uint8_t)(((uint32_t)shift + last_carry * carry_multiplier) & 0xFF);
+ bit_shift_result[i] = res;
+ cols.bit_shift_result[i] = F::from_canonical_u8(res).val;
+ last_carry = (uint32_t)carry;
+ }
+ // for (uintptr_t i = 0; i < WORD_SIZE; ++i)
+ // {
+ // assert(cols.a[i] == cols.bit_shift_result[i]);
+ // }
+ // // Range checks.
+ // blu.add_u8_range_checks(event.shard, &byte_shift_result);
+ // blu.add_u8_range_checks(event.shard, &bit_shift_result);
+ // blu.add_u8_range_checks(event.shard, &shr_carry_output_carry);
+ // blu.add_u8_range_checks(event.shard, &shr_carry_output_shifted_byte);
+ }
+}
+} // namespace sp1::sr
\ No newline at end of file
diff --git a/crates/core/machine/include/sys.hpp b/crates/core/machine/include/sys.hpp
new file mode 100644
index 0000000000..2a6f56166b
--- /dev/null
+++ b/crates/core/machine/include/sys.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "add_sub.hpp"
+#include "bitwise.hpp"
+#include "cpu.hpp"
+#include "lt.hpp"
+#include "memory.hpp"
+#include "mul.hpp"
+#include "sll.hpp"
+#include "sp1-core-machine-sys-cbindgen.hpp"
+#include "sr.hpp"
+#include "memory_local.hpp"
+#include "memory_global.hpp"
+#include "syscall.hpp"
diff --git a/crates/core/machine/include/syscall.hpp b/crates/core/machine/include/syscall.hpp
new file mode 100644
index 0000000000..caa91b32f8
--- /dev/null
+++ b/crates/core/machine/include/syscall.hpp
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "prelude.hpp"
+#include "utils.hpp"
+#include "bb31_septic_extension_t.hpp"
+
+namespace sp1_core_machine_sys::syscall {
+ template __SP1_HOSTDEV__ void populate_syscall(GlobalInteractionOperation* cols, const SyscallEvent* event, bool is_receive) {
+ EF7 x_start;
+
+ {
+ x_start.value[0] = F::from_canonical_u32(event->shard + 8 * (1 << 24));
+ x_start.value[1] = F::from_canonical_u32(event->clk & ((1 << 16) - 1));
+ x_start.value[2] = F::from_canonical_u32((event->clk) >> 16);
+ x_start.value[3] = F::from_canonical_u32(event->syscall_id);
+ x_start.value[4] = F::from_canonical_u32(event->arg1);
+ x_start.value[5] = F::from_canonical_u32(event->arg2);
+ x_start.value[6] = F::zero();
+ }
+
+ #pragma unroll(1)
+ for(uint32_t offset = 0 ; offset < 256 ; offset++) {
+ EF7 x_trial = x_start.universal_hash();
+ EF7 y_sq = x_trial.curve_formula();
+ F y_sq_pow_r = y_sq.pow_r();
+ F is_square = y_sq_pow_r ^ 1006632960;
+ if(is_square == F::one()) {
+ EF7 y = y_sq.sqrt(y_sq_pow_r);
+ if (y.is_exception()) {
+ x_start += F::from_canonical_u32(1 << 16);
+ continue;
+ }
+ if (y.is_receive() != is_receive) {
+ y = EF7::zero() - y;
+ }
+ // x_trial, y
+ for(uint32_t idx = 0 ; idx < 8 ; idx++ ) {
+ cols->offset_bits[idx] = F::from_canonical_u32((offset >> idx) & 1);
+ }
+ for(uintptr_t i = 0 ; i < 7 ; i++) {
+ cols->x_coordinate._0[i] = x_trial.value[i];
+ cols->y_coordinate._0[i] = y.value[i];
+ }
+ uint32_t range_check_value;
+ if (is_receive) {
+ range_check_value = y.value[6].as_canonical_u32() - 1;
+ } else {
+ range_check_value = y.value[6].as_canonical_u32() - (F::MOD + 1) / 2;
+ }
+ F top_4_bits = F::zero();
+ for(uint32_t idx = 0 ; idx < 30 ; idx++) {
+ cols->y6_bit_decomp[idx] = F::from_canonical_u32((range_check_value >> idx) & 1);
+ if (idx >= 26) {
+ top_4_bits += cols->y6_bit_decomp[idx];
+ }
+ }
+ top_4_bits -= F::from_canonical_u32(4);
+ cols->range_check_witness = top_4_bits.reciprocal();
+ return;
+ }
+ x_start += F::from_canonical_u32(1 << 16);
+ }
+ assert(false);
+ }
+
+ template
+ __SP1_HOSTDEV__ void event_to_row(const SyscallEvent* event, const bool is_receive, SyscallCols* cols) {
+ populate_syscall(&cols->global_interaction_cols, event, is_receive);
+ cols->shard = F::from_canonical_u32(event->shard);
+ cols->clk_16 = F::from_canonical_u32(event->clk & ((1 << 16) - 1));
+ cols->clk_8 = F::from_canonical_u32((event->clk) >> 16);
+ cols->syscall_id = F::from_canonical_u32(event->syscall_id);
+ cols->arg1 = F::from_canonical_u32(event->arg1);
+ cols->arg2 = F::from_canonical_u32(event->arg2);
+ cols->is_real = F::one();
+ }
+} // namespace sp1::memory_local
diff --git a/crates/core/machine/include/utils.hpp b/crates/core/machine/include/utils.hpp
new file mode 100644
index 0000000000..7f798ce314
--- /dev/null
+++ b/crates/core/machine/include/utils.hpp
@@ -0,0 +1,134 @@
+#pragma once
+
+#include
+#include
+
+#include "prelude.hpp"
+
+namespace sp1_core_machine_sys {
+
+// Compiles to a no-op with -O3 and the like.
+__SP1_HOSTDEV__ __SP1_INLINE__ array_t u32_to_le_bytes(uint32_t n) {
+ return {
+ (uint8_t)(n >> 8 * 0),
+ (uint8_t)(n >> 8 * 1),
+ (uint8_t)(n >> 8 * 2),
+ (uint8_t)(n >> 8 * 3),
+ };
+}
+
+__SP1_HOSTDEV__ __SP1_INLINE__ array_t u64_to_le_bytes(uint64_t n) {
+ return {
+ (uint8_t)(n >> 8 * 0),
+ (uint8_t)(n >> 8 * 1),
+ (uint8_t)(n >> 8 * 2),
+ (uint8_t)(n >> 8 * 3),
+ (uint8_t)(n >> 8 * 4),
+ (uint8_t)(n >> 8 * 5),
+ (uint8_t)(n >> 8 * 6),
+ (uint8_t)(n >> 8 * 7),
+ };
+}
+
+/// Shifts a byte to the right and returns both the shifted byte and the bits that carried.
+__SP1_HOSTDEV__ __SP1_INLINE__ std::tuple