Skip to content

[Refactor] Universal task #1680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open

[Refactor] Universal task #1680

wants to merge 5 commits into from

Conversation

noel2004
Copy link
Member

@noel2004 noel2004 commented Jun 16, 2025

The refactoring of zkvm prover for "universal tasks", continue with the updates in #1682

The update is focus on the rust part:

  • Re-organize the rust codes under crates directory
  • All rust codes use unified workspace so there would be less pain for handling dependencies issues
  • Coordinators now would load libzkp for handling universal tasks

Summary by CodeRabbit

  • New Features

    • Introduced a modular Rust workspace with new crates for zero-knowledge proof tasks, including core libraries and a C-compatible library.
    • Added comprehensive Rust and Go interfaces for generating and verifying universal ZKP tasks, proofs, and metadata.
    • Implemented an asynchronous RPC client for L2 Ethereum-like nodes, supporting block and storage witness fetching.
    • Provided Dockerfile and build system updates for streamlined multi-crate builds and integration.
    • Added configuration templates and documentation for easier setup and testing.
  • Bug Fixes

    • Improved error handling and memory safety in FFI boundaries.
    • Enhanced handling of empty data and pointer safety in Go and Rust interop.
  • Refactor

    • Migrated from monolithic to modular crate structure, consolidating and reorganizing code for maintainability.
    • Replaced legacy code and removed deprecated files to reflect the new workspace structure.
    • Unified proof generation logic and improved code clarity in proof handler modules.
  • Chores

    • Updated toolchain and dependency management for consistency across the workspace.
    • Revised Makefile and build scripts to support the new project structure and version extraction.
  • Documentation

    • Added README and configuration templates to guide users in setting up and testing the prover system.

Copy link

coderabbitai bot commented Jun 16, 2025

Walkthrough

This change introduces a new Rust workspace structure, migrating the zero-knowledge proof (ZKP) and related logic from common/libzkp/impl to a modularized crates/ directory with separate crates for libzkp, libzkp-c (C FFI), l2geth, and prover-bin. The build system, Dockerfiles, and Makefiles are updated accordingly, and new APIs, FFI interfaces, and proof task abstractions are provided.

Changes

File(s) / Group Change Summary
Cargo.toml, crates/*/Cargo.toml, rust-toolchain Introduced new Rust workspace with modular crates, unified toolchain, and workspace-wide dependency management.
common/libzkp/impl/* Deleted old Rust ZKP implementation, FFI, Makefile, and toolchain pinning.
common/libzkp/Makefile, common/libzkp/lib.go, common/libzkp/universal_task.go, common/libzkp/mock_universal_task.go Added new Makefile, updated Go FFI interface, and added universal task helpers.
crates/libzkp/* Introduced new Rust ZKP core crate with modularized proof, task, and verification logic, including new APIs and error handling.
crates/libzkp_c/* Added new C FFI crate exposing ZKP, universal task, and memory management APIs for integration with Go and C.
crates/l2geth/* Added Rust crate for L2Geth RPC client with async runtime, config, and chunk interpreter traits.
crates/prover-bin/* Added new prover binary crate, refactored error handling to use eyre, and modularized circuit handler logic.
build/dockerfiles/* Updated Dockerfiles to accommodate new crate structure, build paths, and shared library handling.
coordinator/Makefile, zkvm-prover/Makefile, zkvm-prover/print_high_zkvm_version.sh Updated make/build scripts to use new workspace paths and versioning.
zkvm-prover/.cargo/config.toml, zkvm-prover/rust-toolchain Cleaned up cargo config, removed toolchain pinning.
zkvm-prover/config.json.template, crates/prover-bin/README.md Added configuration and documentation templates.
coordinator/test/mock_prover.go Updated mock prover to use unified proof/task handling and universal task markers.

Sequence Diagram(s)

sequenceDiagram
    participant Coordinator
    participant GoLibZKP
    participant libzkp-c (FFI)
    participant libzkp (Rust)
    participant l2geth (Rust)
    participant ProverBin

    Coordinator->>GoLibZKP: Request GenerateUniversalTask / Proof Verification
    GoLibZKP->>libzkp-c (FFI): Call gen_universal_task / verify_*_proof
    libzkp-c (FFI)->>libzkp (Rust): Dispatch to Rust logic
    libzkp (Rust)->>l2geth (Rust): (if needed) Fetch block/state via RPC
    libzkp (Rust)-->>libzkp-c (FFI): Return result (task, metadata, hash, or verification)
    libzkp-c (FFI)-->>GoLibZKP: Return result via FFI
    GoLibZKP-->>Coordinator: Return result

    ProverBin->>libzkp (Rust): Use universal task/proof APIs for proving
Loading

Possibly related PRs

Suggested labels

bump-version

Suggested reviewers

  • georgehao
  • zimpha

Poem

Hopping through crates, the rabbit found
Proofs and tasks, all safe and sound.
From C to Go, through FFI’s gate,
Universal tasks now integrate.
Docker builds anew,
Modular work to do—
Rusty paws, your ZKP’s up-to-date! 🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (1.64.8)

level=error msg="Running error: context loading failed: no go files to analyze: running go mod tidy may solve the problem"

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

[profile.release]
opt-level = 3

[patch."https://github.com/openvm-org/stark-backend.git"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reading. (gpu libs need to be patched)

verify_proof(proof, fork_name, TaskType::Chunk)
/// Turn the coordinator's chunk task into a json string for formal chunk proving
/// task (with full witnesses)
pub fn interpret_chunk_task(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reading. interpret: Not a name easy to understand. is it "check_and_fulfill"?


/// A wrapper around the actual inner proof.
#[derive(Clone, Serialize, Deserialize)]
pub struct WrappedProof<Metadata> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this moved or copied from zkvm-prover?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh same codes. Can we deduplicate it?

}
}

impl<Metadata: ProofMetadata> WrappedProof<Metadata> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my opinion, sanity_check should not happen like this.

As long as the proof.pi == proving_task.pi (and it passes some universial check), it is a good proof. It is proving_task building phase that it should check the consistency between proving_task.pi <-> proving_task.metadata.

/// Defines a proving task for batch proof generation, the format
/// is compatible with both pre-euclidv2 and euclidv2
#[derive(Clone, serde::Deserialize, serde::Serialize)]
pub struct BatchProvingTask {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this struct removed from zkvm-prover?

@@ -0,0 +1,26 @@
import json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file can be removed. Old useless script.


### Some tests would try to generate the proofs it needed and cache them under this directory

### Use `make clean-test-cache` to clean the cached proof files
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure whether it is outdated. make clean-test-cache. reading.

@@ -0,0 +1,66 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we really want to add these 8 json files, we 'd better rename the dir from "phase2" to "euclidv2".

char* universal_task;
char* metadata;
char expected_pi_hash[32];
} HandlingResult;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"HandlingResult" the name not very clear.

@@ -0,0 +1,3 @@
GOOSE_DRIVER=postgres
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these dababase local files can be added in second PR later.

@@ -0,0 +1,34 @@
[app_fri_params.fri_params]
log_blowup = 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these openvm.toml files are for local testing?

They can be added in later PRs.

@lispc
Copy link
Contributor

lispc commented Jun 16, 2025

overall comments:

  1. add some high level desc so infra developers can have a better understanding. Highlight breaking changes like "need a l2geth url in config"
  2. split it into multi PRs: (1) coordinator & libzkp changes (2) provers changes (3?) integration tests & local testing changes? We first only merge and deploy first one.
  3. need to patch gpu libs still
  4. There are some duplicates codes here and zkvm-prover. Need to pay attention to.
  5. Try remove "metadata" from Proof. If needed, we can first file a standalone PR (db changes needed?) before this one.

Cargo.toml Outdated
once_cell = "1.20"
base64 = "0.22"

#TODO: upgrade when Feyman
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feyman -> Feynman

@noel2004 noel2004 marked this pull request as ready for review June 22, 2025 13:21
@codecov-commenter
Copy link

codecov-commenter commented Jun 22, 2025

Codecov Report

Attention: Patch coverage is 70.96774% with 9 lines in your changes missing coverage. Please review.

Project coverage is 40.16%. Comparing base (d2f7663) to head (bdc2867).

Files with missing lines Patch % Lines
coordinator/test/mock_prover.go 70.96% 9 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1680      +/-   ##
===========================================
+ Coverage    40.05%   40.16%   +0.10%     
===========================================
  Files          232      232              
  Lines        18502    18505       +3     
===========================================
+ Hits          7411     7432      +21     
+ Misses       10369    10345      -24     
- Partials       722      728       +6     
Flag Coverage Δ
common 29.67% <ø> (-0.08%) ⬇️
coordinator 34.66% <70.96%> (+0.62%) ⬆️
database 42.05% <ø> (ø)
rollup 46.29% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

🔭 Outside diff range comments (1)
build/dockerfiles/prover.Dockerfile (1)

17-21: Mismatch between build and copy paths
The builder stage runs make prover in /src/zkvm-prover, producing /src/zkvm-prover/target/release/prover, but the runtime stage copies from /src/target/release/prover. This will fail unless the build output path is updated.

Apply one of the following fixes:

# Option A: Build at workspace root
-RUN cd /src/zkvm-prover && make prover
+RUN cd /src && make prover

# Option B: Copy from the sub-crate output
-COPY --from=builder /src/target/release/prover /usr/local/bin/
+COPY --from=builder /src/zkvm-prover/target/release/prover /usr/local/bin/
♻️ Duplicate comments (2)
zkvm-prover/.cargo/config.toml (1)

32-32: Duplicate patch entry follows same pattern
This p3-bn254-fr override uses the same Git/tag approach as above. The feedback on SSH vs. HTTPS and pinning applies here too.

Cargo.toml (1)

55-55: Fix the typo flagged in previous reviews.

As noted in previous reviews, "Feyman" should be "Feynman".

-#TODO: upgrade when Feyman
+#TODO: upgrade when Feynman
🧹 Nitpick comments (16)
zkvm-prover/.cargo/config.toml (2)

2-4: Ensure reproducible and CI-friendly patch overrides
Using SSH-based Git URLs and branch names can hinder reproducibility and break CI if SSH keys aren’t set up. Consider switching to HTTPS URLs or pinning to specific commit SHAs/tags for deterministic builds.


6-31: Consolidate and lock Plonky3 GPU dependencies
This block overrides many Plonky3 crates to a single Git repo/tag. Ensure your CI has access to these repos, and consider pinning to immutable refs (rev = "<commit>") instead of tags to avoid accidental drift.

zkvm-prover/print_high_zkvm_version.sh (1)

4-4: Modernize command substitution and quoting
Use $(…) instead of backticks and quote expansions to prevent word-splitting on spaces. For example:

-higher_zkvm_item=`grep "zkvm-prover" ../Cargo.lock | sort | uniq | awk -F "[#=]" '{print $3" "$4}' | sort -k 1 | tail -n 1`
+higher_zkvm_item=$(grep "zkvm-prover" ../Cargo.lock \
+  | sort -u \
+  | awk -F"[#=]" '{print $3 " " $4}' \
+  | sort -k1 \
+  | tail -n1)
crates/prover-bin/README.md (2)

1-3: Fix grammar and spelling in Prover description

-A runnable zkvm prover which can communicate with coordinator, receving proving task and generate proof
+A runnable zkvm prover that communicates with a coordinator to receive proving tasks and generate proofs.

7-11: Refine Testing section for clarity and formatting
Convert steps into a bullet list, fix typos, and reference the actual template file:

- Get the url of the endpoint of coordinator and a rpc endpoint response to the cooresponding chain
- Build a `config.json` file with previous knowledge from the template in current directory
- Call `make test_run`

+ ## Testing
+
+ - Obtain the coordinator endpoint URL and an RPC endpoint for the corresponding chain.
+ - Create `config.json` based on `config.template.json` in this directory.
+ - Run `make test_run`.
crates/l2geth/Cargo.toml (2)

8-11: Inconsistent dependency version management.

The manifest mixes specific versions with workspace dependencies inconsistently. Consider using workspace dependencies for commonly used crates like tokio and async-trait to ensure version consistency across the workspace.

-tokio = {version = "1", features = ["rt-multi-thread"]}
-async-trait = "0.1"
+tokio = { workspace = true, features = ["rt-multi-thread"]}
+async-trait.workspace = true

Also add these to the root workspace Cargo.toml if not already present.


25-27: Remove trailing empty lines.

Multiple empty lines at the end of the file should be cleaned up for consistency.

-

-
crates/prover-bin/Cargo.toml (2)

1-4: Consider aligning package name with directory name and using workspace version.

The package name "prover" doesn't match the directory name "prover-bin", which could cause confusion. Also consider using workspace version inheritance for consistency.

 [package]
-name = "prover"
-version = "0.1.0"
-edition = "2021"
+name = "prover-bin"
+version.workspace = true
+edition.workspace = true

If keeping the "prover" name is intentional (e.g., for the binary name), consider adding a comment explaining the naming choice.


19-34: Consider using workspace dependencies for commonly used crates.

Many of these dependencies are likely used across multiple crates in the workspace. Consider moving them to workspace dependencies for version consistency.

Crates like reqwest, tokio, clap, hex, rand, async-trait, http, and url are commonly used and would benefit from workspace-level version management. Add these to the root Cargo.toml workspace dependencies section and reference them here with workspace = true.

common/libzkp/universal_task.go (1)

30-33: Consider using copy for better performance.

The manual loop for copying the 32-byte hash could be replaced with Go's built-in copy function for better performance and readability.

 	// Convert C array to Go slice
 	piHash := make([]byte, 32)
-	for i := 0; i < 32; i++ {
-		piHash[i] = byte(result.expected_pi_hash[i])
-	}
+	copy(piHash, (*[32]byte)(unsafe.Pointer(&result.expected_pi_hash[0]))[:])

Note: This requires importing unsafe package. The current implementation is also correct and more readable, so this is optional.

crates/l2geth/src/lib.rs (2)

14-19: Improve error message for better debugging.

The panic message "must has been inited" has grammatical issues and could be more descriptive for debugging purposes.

 pub fn get_client() -> rpc_client::RpcClient<'static> {
     GLOBAL_L2GETH_CLI
         .get()
-        .expect("must has been inited")
+        .expect("L2Geth client has not been initialized. Call init() first.")
         .get_client()
 }

6-6: Consider thread safety implications of the global singleton.

While OnceLock provides thread-safe initialization, consider documenting the intended usage pattern and any thread safety guarantees of the underlying RpcClientCore.

Add documentation to clarify:

  • Whether multiple threads can safely call get_client() concurrently
  • If the returned RpcClient instances are thread-safe
  • The intended lifecycle of the global client (when it should be initialized, if it can be re-initialized, etc.)

Consider adding these details in module-level documentation.

crates/libzkp/src/tasks/chunk_interpreter.rs (2)

4-4: Fix typo in comment.

"cirtical" should be "critical".

-/// An interpreter which is cirtical in translating chunk data
+/// An interpreter which is critical in translating chunk data

21-21: Fix typo in parameter name.

"intepreter" should be "interpreter".

-    fn try_from_with_interpret(value: T, intepreter: impl ChunkInterpreter) -> Result<Self>;
+    fn try_from_with_interpret(value: T, interpreter: impl ChunkInterpreter) -> Result<Self>;
crates/libzkp/src/lib.rs (1)

64-64: Improve error message to include valid task types.

The error message could be more helpful by listing the valid task types.

-        _ => return Err(eyre::eyre!("unrecognized task type {task_type}")),
+        _ => return Err(eyre::eyre!("unrecognized task type {task_type}. Valid types: {} (Chunk), {} (Batch), {} (Bundle)", TaskType::Chunk as i32, TaskType::Batch as i32, TaskType::Bundle as i32)),
crates/l2geth/src/rpc_client.rs (1)

193-212: Consider making tests more maintainable

The tests use hardcoded block hashes with comments indicating specific dates. These might become invalid if the test network is reset or reorganized.

Consider fetching recent blocks dynamically:

// Fetch the latest block and use its parent
let latest_block = client.provider.get_block_number().await?;
let block = client.provider.get_block_by_number(latest_block - 1, false).await?.unwrap();
let block_hash = block.header.hash;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2f7663 and bdc2867.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • common/libzkp/impl/Cargo.lock is excluded by !**/*.lock
  • crates/libzkp/src/plonk_verifier_0.11.4.bin is excluded by !**/*.bin
📒 Files selected for processing (46)
  • Cargo.toml (1 hunks)
  • build/dockerfiles/coordinator-api.Dockerfile (3 hunks)
  • build/dockerfiles/prover.Dockerfile (1 hunks)
  • common/libzkp/Makefile (1 hunks)
  • common/libzkp/impl/Cargo.toml (0 hunks)
  • common/libzkp/impl/Makefile (0 hunks)
  • common/libzkp/impl/rust-toolchain (0 hunks)
  • common/libzkp/impl/src/lib.rs (0 hunks)
  • common/libzkp/impl/src/utils.rs (0 hunks)
  • common/libzkp/lib.go (3 hunks)
  • common/libzkp/mock_universal_task.go (1 hunks)
  • common/libzkp/universal_task.go (1 hunks)
  • coordinator/Makefile (2 hunks)
  • coordinator/test/mock_prover.go (3 hunks)
  • crates/l2geth/Cargo.toml (1 hunks)
  • crates/l2geth/src/lib.rs (1 hunks)
  • crates/l2geth/src/rpc_client.rs (1 hunks)
  • crates/libzkp/Cargo.toml (1 hunks)
  • crates/libzkp/src/lib.rs (1 hunks)
  • crates/libzkp/src/proofs.rs (1 hunks)
  • crates/libzkp/src/tasks.rs (1 hunks)
  • crates/libzkp/src/tasks/batch.rs (1 hunks)
  • crates/libzkp/src/tasks/batch/utils.rs (1 hunks)
  • crates/libzkp/src/tasks/bundle.rs (1 hunks)
  • crates/libzkp/src/tasks/chunk.rs (1 hunks)
  • crates/libzkp/src/tasks/chunk_interpreter.rs (1 hunks)
  • crates/libzkp/src/utils.rs (1 hunks)
  • crates/libzkp/src/verifier.rs (3 hunks)
  • crates/libzkp/src/verifier/euclidv2.rs (2 hunks)
  • crates/libzkp_c/Cargo.toml (1 hunks)
  • crates/libzkp_c/src/lib.rs (1 hunks)
  • crates/libzkp_c/src/utils.rs (1 hunks)
  • crates/prover-bin/Cargo.toml (1 hunks)
  • crates/prover-bin/README.md (1 hunks)
  • crates/prover-bin/src/main.rs (2 hunks)
  • crates/prover-bin/src/prover.rs (3 hunks)
  • crates/prover-bin/src/types.rs (0 hunks)
  • crates/prover-bin/src/zk_circuits_handler.rs (1 hunks)
  • crates/prover-bin/src/zk_circuits_handler/euclidV2.rs (2 hunks)
  • rust-toolchain (1 hunks)
  • zkvm-prover/.cargo/config.toml (1 hunks)
  • zkvm-prover/Makefile (2 hunks)
  • zkvm-prover/config.json.template (1 hunks)
  • zkvm-prover/print_high_zkvm_version.sh (1 hunks)
  • zkvm-prover/rust-toolchain (0 hunks)
  • zkvm-prover/src/zk_circuits_handler.rs (0 hunks)
💤 Files with no reviewable changes (8)
  • zkvm-prover/rust-toolchain
  • common/libzkp/impl/rust-toolchain
  • common/libzkp/impl/Makefile
  • crates/prover-bin/src/types.rs
  • common/libzkp/impl/Cargo.toml
  • zkvm-prover/src/zk_circuits_handler.rs
  • common/libzkp/impl/src/lib.rs
  • common/libzkp/impl/src/utils.rs
🧰 Additional context used
🪛 checkmake (0.2.2)
common/libzkp/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: check
🔇 Additional comments (53)
rust-toolchain (1)

1-3: Specify Rust nightly toolchain and targets
Good addition: pinning to nightly-2025-02-14 and declaring cross-compilation targets.

crates/libzkp/src/verifier.rs (3)

5-5: LGTM: Consistent error handling migration.

The switch from anyhow to eyre for error handling aligns with the broader codebase refactoring mentioned in the PR objectives.


16-24: LGTM: Valuable Display implementation for TaskType.

The Display trait implementation provides clear string representations for logging and debugging purposes. The lowercase format matches typical enum display conventions.


74-77: LGTM: Proper error construction with eyre.

The error construction correctly uses eyre::eyre! macro with the same error message format, maintaining functionality while using the new error handling library.

crates/prover-bin/src/main.rs (2)

29-29: LGTM: Consistent error handling in main function.

The return type change to eyre::Result<()> is consistent with the broader error handling migration across the codebase.


42-45: LGTM: Improved error handling with descriptive messaging.

The explicit error mapping with the descriptive message "build prover fail: {e}" provides better debugging information when the prover build fails.

zkvm-prover/Makefile (2)

4-7: LGTM: Path adjustment for workspace structure.

The path change from ./Cargo.lock to ../Cargo.lock correctly reflects the new workspace structure where the lock file is at the root level.


43-43: LGTM: Test binary path adjustment for workspace.

The path change to ../target/release/deps/prover* aligns with the new workspace build output location.

crates/prover-bin/src/prover.rs (4)

3-4: LGTM: Improved base64 and error handling imports.

The explicit use of BASE64_STANDARD engine provides better clarity than relying on default imports, and the migration to eyre is consistent with the codebase refactoring.


35-35: LGTM: Consistent error mapping with eyre.

The error mapping using eyre::eyre! maintains the same functionality while using the new error handling library.


71-71: LGTM: Explicit base64 engine usage.

Using BASE64_STANDARD explicitly is clearer and more maintainable than relying on implicit defaults.


185-190: Verify removal of "euclid" circuit handler support.

The circuit handler logic now only supports "euclidV2" and removes support for "euclid". This could be a breaking change if existing configurations or deployments rely on the "euclid" handler.

#!/bin/bash
# Description: Search for usage of "euclid" handler in the codebase to verify impact
# Expected: Find any references that might break due to handler removal

echo "=== Searching for 'euclid' handler references ==="
rg -i "euclid" --type json --type yaml --type toml
echo

echo "=== Searching for 'euclid' in configuration files ==="
fd -e json -e yaml -e toml -e conf | xargs rg -l -i "euclid" 2>/dev/null || echo "No configuration files found with 'euclid'"
echo

echo "=== Searching for 'euclid' in source code ==="
rg -A 3 -B 3 '"euclid"' --type rust --type go
crates/libzkp_c/Cargo.toml (1)

1-14: LGTM: Well-configured C FFI crate.

The manifest is properly structured for a C-compatible FFI library:

  • Workspace inheritance maintains consistency
  • cdylib crate type is correct for C interoperability
  • Dependencies on libzkp, l2geth, and tracing are appropriate for the FFI layer's functionality
crates/libzkp/src/verifier/euclidv2.rs (4)

3-8: LGTM: Clean refactoring to new crate structure.

The migration from anyhow to eyre and reorganization of imports to use the new local crate modules aligns well with the workspace restructuring.


40-44: LGTM: Simplified proof handling.

Removing the .unwrap() calls suggests that as_root_proof() now returns the value directly rather than an Option, which is a cleaner API design.


52-52: LGTM: Consistent error handling.

The switch to eyre::eyre! is consistent with the error handling changes throughout the file.


56-62: LGTM: Updated base64 usage.

Using BASE64_STANDARD engine is the recommended approach in recent versions of the base64 crate.

crates/libzkp/Cargo.toml (1)

1-23: LGTM: Well-structured crate manifest.

The Cargo.toml is properly configured with:

  • Appropriate workspace inheritance for version and edition
  • Relevant ZKP and cryptographic dependencies
  • Proper feature specifications (e.g., raw_value for serde_json)
  • Reasonable version constraints for external crates
common/libzkp/Makefile (2)

3-6: LGTM: Build process correctly targets the new crate structure.

The build target properly compiles the libzkp-c package and copies the shared library to the expected location for integration with the coordinator.


15-17: LGTM: Comprehensive linting configuration.

The clippy target uses appropriate flags to ensure code quality with --all-features and treating warnings as errors.

coordinator/test/mock_prover.go (4)

164-164: LGTM: Added universal task support to task requests.

The addition of "universal": true aligns with the new universal task architecture described in the PR objectives.


194-194: LGTM: Consistent universal task parameter.

The universal task parameter is correctly added to the tryGetProverTask request as well.


210-241: LGTM: Simplified and unified proof marshaling logic.

The refactored code eliminates code duplication by:

  • Using fallthrough for chunk/batch cases that share the same proof type (OpenVMProof)
  • Consolidating the proof generation logic
  • Maintaining clear separation between success and failure cases

This aligns well with the universal task refactoring objectives.


249-249: LGTM: Added universal flag to proof submission.

The Universal: true field in SubmitProofParameter is consistent with the universal task support added throughout the coordinator.

coordinator/Makefile (2)

36-37: I’ll re-run the search without file-type filters to catch any references:

#!/bin/bash
# Search for any occurrences of coordinator_api_skip_libzkp across the repo
echo "Checking for references to coordinator_api_skip_libzkp across entire codebase:"
rg -n "coordinator_api_skip_libzkp" || echo "No matches found."

7-11: ```shell
#!/bin/bash
set -e

Locate Cargo.lock in the repository

echo "Locating Cargo.lock..."
CARGO_LOCK=$(find . -type f -name Cargo.lock | head -n1)
if [ -z "$CARGO_LOCK" ]; then
echo "ERROR: No Cargo.lock found"
exit 1
fi
echo "Using Cargo.lock at: $CARGO_LOCK"
echo

Show entries around zkvm-prover

echo "=== zkvm-prover entries ==="
grep -A2 -B2 'zkvm-prover' "$CARGO_LOCK" || echo "(no zkvm-prover entries found)"
echo

Show entries around openvm.git

echo "=== openvm.git entries ==="
grep -A2 -B2 'openvm.git' "$CARGO_LOCK" || echo "(no openvm.git entries found)"
echo

Test version extraction logic for zkvm-prover

echo "Extracted ZKVM_VERSION using current logic:"
grep -m1 'zkvm-prover' "$CARGO_LOCK" | cut -d '"' -f2 | cut -c1-7 || echo "(extraction failed)"
echo

Test version extraction logic for openvm.git

echo "Extracted OPENVM_VERSION using current logic:"
grep -m1 'openvm.git' "$CARGO_LOCK" | cut -d '"' -f2 | cut -c1-7 || echo "(extraction failed)"


</details>
<details>
<summary>common/libzkp/universal_task.go (1)</summary>

`11-36`: **LGTM! Proper FFI implementation with good memory management.**

The function correctly handles:
- Memory management with deferred cleanup of C strings and result
- Error checking by inspecting `result.ok`
- Safe type conversions from C types to Go types
- Proper handling of fixed-size byte array conversion

The build tag `!mock_verifier` allows for flexible testing scenarios.

</details>
<details>
<summary>crates/libzkp/src/tasks/bundle.rs (1)</summary>

`52-104`: **Well-structured validation logic.**

The `precheck_and_build_metadata` method implements thorough validation:
- Verifies chain ID consistency
- Ensures state roots are properly chained
- Validates batch hash chaining

</details>
<details>
<summary>crates/prover-bin/src/zk_circuits_handler/euclidV2.rs (1)</summary>

`50-72`: **Clean refactoring to unified proof generation.**

The refactoring successfully:
- Eliminates code duplication by deserializing once into a generic `ProvingTask`
- Unifies proof generation through a single `gen_proof_universal` method
- Simplifies the control flow

</details>
<details>
<summary>build/dockerfiles/coordinator-api.Dockerfile (3)</summary>

`6-8`: **LGTM! Clean migration to workspace structure.**

The change from copying specific `common/libzkp/impl` directory to the entire `crates` directory and workspace configuration files aligns well with the new workspace-based approach.

---

`22-24`: **LGTM! Targeted build approach is more specific.**

Building the specific `libzkp-c` package instead of a generic build is clearer and more maintainable. This aligns with the modular crate structure.

---

`43-46`: **LGTM! Updated build process reflects new architecture.**

The changes properly integrate the new libzkp shared library from the zkp-builder stage and update the coordinator build process to work with the new structure. Moving the entire lib directory is a good approach for packaging.

</details>
<details>
<summary>crates/libzkp/src/tasks/chunk_interpreter.rs (2)</summary>

`7-18`: **LGTM! Well-designed trait with sensible defaults.**

The trait design with default error-returning implementations is a good pattern for optional functionality that can be overridden by specific implementations.

---

`24-26`: **LGTM! Clean placeholder implementation.**

The `DummyInterpreter` provides a good fallback implementation using the default trait methods.

</details>
<details>
<summary>Cargo.toml (2)</summary>

`1-7`: **LGTM! Well-structured workspace configuration.**

The workspace setup with 4 member crates aligns perfectly with the modular architecture described in the PR objectives. This will centralize dependency management effectively.

---

`63-66`: **LGTM! Appropriate performance optimization profile.**

The maxperf profile with fat LTO and single codegen units is well-suited for zero-knowledge proof operations where maximum performance is critical.

</details>
<details>
<summary>common/libzkp/lib.go (4)</summary>

`7-7`: **LGTM! Updated header path reflects new structure.**

The header include path update aligns with the migration from the old `common/libzkp/impl` to the new workspace structure.

---

`78-96`: **LGTM! Good type safety improvements.**

The task type constants and conversion function provide better type safety and maintainability by centralizing the mapping between Go and Rust enum values.

---

`99-101`: **LGTM! Clean abstraction with wrapper function.**

The refactoring to use a wrapper function allows for better separation of concerns and enables the mock implementation approach mentioned in the AI summary.

---

`111-114`: **LGTM! Important safety improvement for empty slices.**

The conditional pointer handling prevents unsafe pointer usage when `vkData` is empty, which is a good defensive programming practice.

</details>
<details>
<summary>crates/prover-bin/src/zk_circuits_handler.rs (3)</summary>

`12-17`: **LGTM! Clean async trait design.**

The `CircuitsHandler` trait provides a well-designed async interface for VK retrieval and proof generation, which is appropriate for potentially long-running cryptographic operations.

---

`19-22`: **LGTM! Extensible phase enumeration.**

The `Phase` enum design allows for easy extension to support different proving phases or versions, which aligns with the evolutionary nature of zkVM systems.

---

`25-37`: **LGTM! Consistent and well-structured configuration methods.**

The phase specification methods for chunk, batch, and bundle tasks follow a consistent pattern with appropriate workspace-relative paths and consistent segment length configuration. The use of `(1 << 22) - 100` as segment length across all task types suggests this is a well-tested configuration value.



Also applies to: 39-51, 53-66

</details>
<details>
<summary>crates/libzkp/src/lib.rs (3)</summary>

`14-26`: **LGTM!**

The function correctly handles deserialization, conversion, and serialization with proper error propagation.

---

`74-96`: **Efficient JSON handling with RawValue.**

Good use of `RawValue` to avoid unnecessary JSON parsing and serialization overhead.

---

`114-121`: Let’s locate the verifier module and inspect the exact `dump_vk` signature:


```shell
#!/bin/bash
# 1. Find where the verifier module is declared
rg -n "mod verifier" crates/libzkp/src/lib.rs

# 2. Check if it's a file or directory, then search for dump_vk
if [ -f crates/libzkp/src/verifier.rs ]; then
  echo "✔ Found verifier.rs"
  rg -n "fn dump_vk" crates/libzkp/src/verifier.rs
elif [ -d crates/libzkp/src/verifier ]; then
  echo "✔ Found verifier/ directory"
  rg -n "fn dump_vk" crates/libzkp/src/verifier
else
  echo "⚠️ No verifier module found under crates/libzkp/src"
fi
crates/libzkp/src/tasks/batch.rs (1)

103-174: Well-structured KZG proof generation with comprehensive validation.

The method properly validates fork compatibility and verifies provided KZG data against calculated values.

crates/libzkp/src/tasks/chunk.rs (2)

10-133: Well-structured chunk task implementation.

The chunk task types and conversion implementations are clean and follow good practices with proper error propagation.


154-156: ```shell
#!/bin/bash

Inspect imports in chunk.rs to locate execute and error types

echo "=== chunk.rs imports (lines 1–50) ==="
sed -n '1,50p' crates/libzkp/src/tasks/chunk.rs || true

Reprint the regex error‐parsing context

echo "=== chunk.rs context (lines 140–220) ==="
sed -n '140,220p' crates/libzkp/src/tasks/chunk.rs || true

Find all references to SparseTrieError in this repo

echo "=== occurrences of SparseTrieError in workspace ==="
rg -n "SparseTrieError" . || true

Locate any local merkle_db crate

echo "=== merkle_db directories (up to depth 4) ==="
find . -maxdepth 4 -type d | grep merkle_db || true

If merkle_db is part of this workspace, search its source

if [ -d "crates/merkle_db" ]; then
echo "=== search in crates/merkle_db for SparseTrieError ==="
rg -n "enum SparseTrieError" crates/merkle_db || true
rg -n "struct SparseTrieError" crates/merkle_db || true
fi

Find the definition of the execute function used in the retry loop

echo "=== execute function definitions in tasks/ ==="
rg -n "fn execute" crates/libzkp/src/tasks || true


</details>
<details>
<summary>crates/libzkp/src/tasks/batch/utils.rs (1)</summary>

`1-16`: **Standard base64 serialization implementation.**

Clean implementation of base64 serialization/deserialization for serde.

</details>
<details>
<summary>crates/libzkp/src/tasks.rs (1)</summary>

`20-76`: **Well-structured universal task generation functions.**

All three generation functions follow a consistent pattern with proper error handling and metadata construction.

</details>
<details>
<summary>crates/libzkp_c/src/lib.rs (1)</summary>

`22-60`: **Good error handling pattern for FFI functions**

The `verify_proof` helper and its wrappers demonstrate proper error handling for FFI - logging errors and returning status codes instead of panicking.

</details>
<details>
<summary>crates/l2geth/src/rpc_client.rs (1)</summary>

`62-82`: **Well-designed async runtime management**

The approach of embedding a tokio runtime within `RpcClientCore` is appropriate for a library that needs to work in synchronous contexts. The multi-threaded runtime configuration is correct for this use case.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +8 to +11
pub(crate) fn c_char_to_vec(c: *const c_char) -> Vec<u8> {
let cstr = unsafe { CStr::from_ptr(c) };
cstr.to_bytes().to_vec()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add null pointer validation for safety.

The function should validate the input pointer before dereferencing to prevent undefined behavior.

Apply this diff to add safety checks:

 pub(crate) fn c_char_to_vec(c: *const c_char) -> Vec<u8> {
+    if c.is_null() {
+        return Vec::new();
+    }
     let cstr = unsafe { CStr::from_ptr(c) };
     cstr.to_bytes().to_vec()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub(crate) fn c_char_to_vec(c: *const c_char) -> Vec<u8> {
let cstr = unsafe { CStr::from_ptr(c) };
cstr.to_bytes().to_vec()
}
pub(crate) fn c_char_to_vec(c: *const c_char) -> Vec<u8> {
if c.is_null() {
return Vec::new();
}
let cstr = unsafe { CStr::from_ptr(c) };
cstr.to_bytes().to_vec()
}
🤖 Prompt for AI Agents
In crates/libzkp_c/src/utils.rs around lines 8 to 11, the function c_char_to_vec
dereferences a raw pointer without checking if it is null, which can cause
undefined behavior. Add a null pointer check at the start of the function to
return an empty Vec or handle the error safely if the pointer is null before
calling CStr::from_ptr. This ensures the function does not dereference a null
pointer.

Comment on lines +3 to +6
pub(crate) fn c_char_to_str(c: *const c_char) -> &'static str {
let cstr = unsafe { CStr::from_ptr(c) };
cstr.to_str().unwrap()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect lifetime and add safety checks.

The function has several critical issues:

  1. Incorrect lifetime: The return type &'static str is incorrect - the string doesn't have static lifetime and this creates a dangling reference.
  2. Missing safety checks: No null pointer validation before dereferencing.
  3. Panic potential: unwrap() will panic on invalid UTF-8, crashing the process.

Apply this diff to fix the safety issues:

-pub(crate) fn c_char_to_str(c: *const c_char) -> &'static str {
-    let cstr = unsafe { CStr::from_ptr(c) };
-    cstr.to_str().unwrap()
+pub(crate) fn c_char_to_str(c: *const c_char) -> Result<&str, std::str::Utf8Error> {
+    if c.is_null() {
+        return Err(std::str::Utf8Error::invalid_utf8_at(0));
+    }
+    let cstr = unsafe { CStr::from_ptr(c) };
+    cstr.to_str()
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/libzkp_c/src/utils.rs around lines 3 to 6, the function c_char_to_str
incorrectly returns a &'static str which can cause dangling references, lacks a
null pointer check before dereferencing, and uses unwrap() that may panic on
invalid UTF-8. Fix this by changing the return type to an Option<&str>, add a
check to return None if the pointer is null, and replace unwrap() with proper
error handling to return None on invalid UTF-8 conversion.

@@ -0,0 +1,17 @@
.PHONY: help fmt clippy test test-ci test-all
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add missing phony targets.

The static analysis correctly identifies that the clean target should be declared as phony, and the conventional all target is missing.

Apply this diff to fix the phony target declarations:

-.PHONY: help fmt clippy test test-ci test-all
+.PHONY: all help fmt clippy test test-ci test-all build clean

+all: build
+
 build:
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)

🤖 Prompt for AI Agents
In common/libzkp/Makefile at line 1, the .PHONY declaration is missing the
'clean' and 'all' targets. Update the .PHONY line to include 'clean' and 'all'
so that these targets are correctly marked as phony, preventing conflicts with
files of the same name.

[dependencies]
tokio = {version = "1", features = ["rt-multi-thread"]}
async-trait = "0.1"
url = ">=2.5.3"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use more specific version constraint for security.

The url dependency uses a loose constraint >=2.5.3 which could allow potentially incompatible major version upgrades.

-url = ">=2.5.3"
+url = "^2.5.3"

The caret requirement ^2.5.3 allows compatible changes within the same major version while preventing breaking changes.

🤖 Prompt for AI Agents
In crates/l2geth/Cargo.toml at line 10, replace the loose version constraint
">=2.5.3" for the url dependency with a caret requirement "^2.5.3" to restrict
updates to compatible versions within the same major version and avoid potential
breaking changes.

[dependencies]
scroll-zkvm-types.workspace = true
scroll-zkvm-prover-euclid.workspace = true
scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", branch = "refactor/scroll" }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Pin the git dependency to a specific commit for reproducible builds.

The git dependency uses a branch reference which can change over time, potentially breaking builds or introducing unexpected changes.

-scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", branch = "refactor/scroll" }
+scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", rev = "abc1234" }

Replace "abc1234" with the actual commit hash you want to pin to. This ensures reproducible builds and prevents unexpected changes.

🤖 Prompt for AI Agents
In crates/prover-bin/Cargo.toml at line 11, the git dependency for
scroll-proving-sdk is currently pinned to a branch, which can lead to
non-reproducible builds. Replace the branch reference with a specific commit
hash by changing the dependency to use "rev = 'commit_hash'" instead of "branch
= 'refactor/scroll'". This pins the dependency to a fixed commit and ensures
consistent builds.

Comment on lines +142 to +150
pub unsafe extern "C" fn gen_wrapped_proof(
proof: *const c_char,
metadata: *const c_char,
vk: *const c_char,
vk_len: usize,
) -> *mut c_char {
let proof_str = c_char_to_str(proof);
let metadata_str = c_char_to_str(metadata);
let vk_data = std::slice::from_raw_parts(vk as *const u8, vk_len);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null pointer validation for vk parameter

The vk pointer is used to create a slice without checking if it's null.

 pub unsafe extern "C" fn gen_wrapped_proof(
     proof: *const c_char,
     metadata: *const c_char,
     vk: *const c_char,
     vk_len: usize,
 ) -> *mut c_char {
+    if vk.is_null() && vk_len > 0 {
+        tracing::error!("vk is null but vk_len is {}", vk_len);
+        return std::ptr::null_mut();
+    }
     let proof_str = c_char_to_str(proof);
     let metadata_str = c_char_to_str(metadata);
     let vk_data = std::slice::from_raw_parts(vk as *const u8, vk_len);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub unsafe extern "C" fn gen_wrapped_proof(
proof: *const c_char,
metadata: *const c_char,
vk: *const c_char,
vk_len: usize,
) -> *mut c_char {
let proof_str = c_char_to_str(proof);
let metadata_str = c_char_to_str(metadata);
let vk_data = std::slice::from_raw_parts(vk as *const u8, vk_len);
pub unsafe extern "C" fn gen_wrapped_proof(
proof: *const c_char,
metadata: *const c_char,
vk: *const c_char,
vk_len: usize,
) -> *mut c_char {
if vk.is_null() && vk_len > 0 {
tracing::error!("vk is null but vk_len is {}", vk_len);
return std::ptr::null_mut();
}
let proof_str = c_char_to_str(proof);
let metadata_str = c_char_to_str(metadata);
let vk_data = std::slice::from_raw_parts(vk as *const u8, vk_len);
// ... rest of function ...
}
🤖 Prompt for AI Agents
In crates/libzkp_c/src/lib.rs around lines 142 to 150, the vk pointer is used to
create a slice without null pointer validation. Add a check to verify if vk is
null before creating the slice. If vk is null, handle the error appropriately,
such as returning a null pointer or an error indicator, to prevent undefined
behavior from dereferencing a null pointer.

Comment on lines +64 to +68
pub unsafe extern "C" fn dump_vk(fork_name: *const c_char, file: *const c_char) {
let fork_name_str = c_char_to_str(fork_name);
let file_str = c_char_to_str(file);
libzkp::dump_vk(fork_name_str, file_str).unwrap();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace unwrap() with error handling

This function can panic if dump_vk fails, which is unsafe in FFI context.

Return an error code:

-pub unsafe extern "C" fn dump_vk(fork_name: *const c_char, file: *const c_char) {
+pub unsafe extern "C" fn dump_vk(fork_name: *const c_char, file: *const c_char) -> c_char {
     let fork_name_str = c_char_to_str(fork_name);
     let file_str = c_char_to_str(file);
-    libzkp::dump_vk(fork_name_str, file_str).unwrap();
+    match libzkp::dump_vk(fork_name_str, file_str) {
+        Ok(_) => true as c_char,
+        Err(e) => {
+            tracing::error!("Failed to dump vk: {:#}", e);
+            false as c_char
+        }
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub unsafe extern "C" fn dump_vk(fork_name: *const c_char, file: *const c_char) {
let fork_name_str = c_char_to_str(fork_name);
let file_str = c_char_to_str(file);
libzkp::dump_vk(fork_name_str, file_str).unwrap();
}
pub unsafe extern "C" fn dump_vk(fork_name: *const c_char, file: *const c_char) -> c_char {
let fork_name_str = c_char_to_str(fork_name);
let file_str = c_char_to_str(file);
match libzkp::dump_vk(fork_name_str, file_str) {
Ok(_) => true as c_char,
Err(e) => {
tracing::error!("Failed to dump vk: {:#}", e);
false as c_char
}
}
}
🤖 Prompt for AI Agents
In crates/libzkp_c/src/lib.rs around lines 64 to 68, the use of unwrap() on the
result of libzkp::dump_vk can cause a panic, which is unsafe in an FFI function.
Replace unwrap() with proper error handling by checking the Result returned by
dump_vk and returning an appropriate error code or status to the caller instead
of panicking.

Comment on lines +115 to +122
if let Ok((pi_hash, task_json, meta_json)) = ret {
let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char);
HandlingResult {
ok: true as c_char,
universal_task: CString::new(task_json).unwrap().into_raw(),
metadata: CString::new(meta_json).unwrap().into_raw(),
expected_pi_hash,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix unsafe type conversion and potential panics

Two issues in this code:

  1. Line 116: Converting u8 to c_char (signed i8) can cause overflow for values > 127
  2. Lines 119-120: CString::new().unwrap() can panic if strings contain null bytes
-        let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char);
+        let expected_pi_hash = pi_hash.0.map(|byte| byte as i8);
         HandlingResult {
             ok: true as c_char,
-            universal_task: CString::new(task_json).unwrap().into_raw(),
-            metadata: CString::new(meta_json).unwrap().into_raw(),
+            universal_task: match CString::new(task_json) {
+                Ok(s) => s.into_raw(),
+                Err(e) => {
+                    tracing::error!("Invalid task_json: {}", e);
+                    return failed_handling_result();
+                }
+            },
+            metadata: match CString::new(meta_json) {
+                Ok(s) => s.into_raw(),
+                Err(e) => {
+                    tracing::error!("Invalid meta_json: {}", e);
+                    return failed_handling_result();
+                }
+            },
             expected_pi_hash,
         }

Also consider using u8 array instead of c_char array in the struct definition to avoid signed/unsigned issues.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Ok((pi_hash, task_json, meta_json)) = ret {
let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char);
HandlingResult {
ok: true as c_char,
universal_task: CString::new(task_json).unwrap().into_raw(),
metadata: CString::new(meta_json).unwrap().into_raw(),
expected_pi_hash,
}
if let Ok((pi_hash, task_json, meta_json)) = ret {
- let expected_pi_hash = pi_hash.0.map(|byte| byte as c_char);
+ let expected_pi_hash = pi_hash.0.map(|byte| byte as i8);
HandlingResult {
ok: true as c_char,
- universal_task: CString::new(task_json).unwrap().into_raw(),
- metadata: CString::new(meta_json).unwrap().into_raw(),
+ universal_task: match CString::new(task_json) {
+ Ok(s) => s.into_raw(),
+ Err(e) => {
+ tracing::error!("Invalid task_json: {}", e);
+ return failed_handling_result();
+ }
+ },
+ metadata: match CString::new(meta_json) {
+ Ok(s) => s.into_raw(),
+ Err(e) => {
+ tracing::error!("Invalid meta_json: {}", e);
+ return failed_handling_result();
+ }
+ },
expected_pi_hash,
}
}
🤖 Prompt for AI Agents
In crates/libzkp_c/src/lib.rs around lines 115 to 122, fix the unsafe conversion
from u8 to c_char by avoiding direct casting that can overflow; instead, handle
bytes as u8 to prevent sign issues. Replace the map converting pi_hash bytes to
c_char with a safe method or change the struct to use a u8 array for
expected_pi_hash. Also, replace CString::new().unwrap() calls with safe error
handling to avoid panics if task_json or meta_json contain null bytes, such as
by checking for null bytes before conversion or returning an error instead of
unwrapping.

Comment on lines +63 to +94
impl AsRootProof for ChunkProof {
fn as_root_proof(&self) -> &RootProof {
self.proof
.as_root_proof()
.expect("batch proof use root proof")
}
}

impl AsRootProof for BatchProof {
fn as_root_proof(&self) -> &RootProof {
self.proof
.as_root_proof()
.expect("batch proof use root proof")
}
}

impl AsEvmProof for BundleProof {
fn as_evm_proof(&self) -> &EvmProof {
self.proof
.as_evm_proof()
.expect("bundle proof use evm proof")
}
}

impl IntoEvmProof for BundleProof {
fn into_evm_proof(self) -> OpenVmEvmProof {
self.proof
.as_evm_proof()
.expect("bundle proof use evm proof")
.clone()
.into()
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider returning Result instead of using expect()

The current implementations panic if the wrong proof type is accessed. This could cause runtime crashes.

Consider changing the trait methods to return Result:

pub trait AsRootProof {
    fn as_root_proof(&self) -> Result<&RootProof, &'static str>;
}

impl AsRootProof for ChunkProof {
    fn as_root_proof(&self) -> Result<&RootProof, &'static str> {
        self.proof
            .as_root_proof()
            .ok_or("chunk proof should use root proof")
    }
}

This allows callers to handle type mismatches gracefully.

🤖 Prompt for AI Agents
In crates/libzkp/src/proofs.rs between lines 63 and 94, the trait methods
as_root_proof and as_evm_proof currently use expect() which causes panics on
type mismatches. Modify the trait definitions to return Result types instead of
references directly. Update all implementations to return Ok with the proof
reference on success or Err with a static error message on failure. This change
will allow callers to handle errors gracefully without runtime panics.

Comment on lines +178 to +200
impl<Metadata: ProofMetadata> WrappedProof<Metadata> {
/// Sanity checks on the wrapped proof:
///
/// - pi_hash computed in host does in fact match pi_hash computed in guest
pub fn sanity_check(&self, fork_name: ForkName) {
let proof_pi = self.proof.public_values();

let expected_pi = self
.metadata
.pi_hash_info()
.pi_hash_by_fork(fork_name)
.0
.as_ref()
.iter()
.map(|&v| v as u32)
.collect::<Vec<_>>();

assert_eq!(
expected_pi, proof_pi,
"pi mismatch: expected={expected_pi:?}, found={proof_pi:?}"
);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Return Result instead of panicking in sanity_check

The assert_eq! will panic if the check fails, which might not be desirable in all contexts.

-    pub fn sanity_check(&self, fork_name: ForkName) {
+    pub fn sanity_check(&self, fork_name: ForkName) -> Result<(), String> {
         let proof_pi = self.proof.public_values();

         let expected_pi = self
             .metadata
             .pi_hash_info()
             .pi_hash_by_fork(fork_name)
             .0
             .as_ref()
             .iter()
             .map(|&v| v as u32)
             .collect::<Vec<_>>();

-        assert_eq!(
-            expected_pi, proof_pi,
-            "pi mismatch: expected={expected_pi:?}, found={proof_pi:?}"
-        );
+        if expected_pi != proof_pi {
+            return Err(format!(
+                "pi mismatch: expected={expected_pi:?}, found={proof_pi:?}"
+            ));
+        }
+        Ok(())
     }

This allows callers to handle validation failures appropriately.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
impl<Metadata: ProofMetadata> WrappedProof<Metadata> {
/// Sanity checks on the wrapped proof:
///
/// - pi_hash computed in host does in fact match pi_hash computed in guest
pub fn sanity_check(&self, fork_name: ForkName) {
let proof_pi = self.proof.public_values();
let expected_pi = self
.metadata
.pi_hash_info()
.pi_hash_by_fork(fork_name)
.0
.as_ref()
.iter()
.map(|&v| v as u32)
.collect::<Vec<_>>();
assert_eq!(
expected_pi, proof_pi,
"pi mismatch: expected={expected_pi:?}, found={proof_pi:?}"
);
}
}
impl<Metadata: ProofMetadata> WrappedProof<Metadata> {
/// Sanity checks on the wrapped proof:
///
/// - pi_hash computed in host does in fact match pi_hash computed in guest
pub fn sanity_check(&self, fork_name: ForkName) -> Result<(), String> {
let proof_pi = self.proof.public_values();
let expected_pi = self
.metadata
.pi_hash_info()
.pi_hash_by_fork(fork_name)
.0
.as_ref()
.iter()
.map(|&v| v as u32)
.collect::<Vec<_>>();
if expected_pi != proof_pi {
return Err(format!(
"pi mismatch: expected={expected_pi:?}, found={proof_pi:?}"
));
}
Ok(())
}
}
🤖 Prompt for AI Agents
In crates/libzkp/src/proofs.rs lines 178 to 200, the sanity_check method uses
assert_eq! which panics on failure. Change the method to return a Result type
instead, returning Ok(()) if the check passes and an Err with a descriptive
error if the pi_hash values do not match. This allows callers to handle
validation failures without panics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants