From 3bde14d2ba0d22527feb44373626b57cb20483dc Mon Sep 17 00:00:00 2001 From: Aditya Bisht Date: Mon, 20 Apr 2026 18:16:23 +0530 Subject: [PATCH 1/3] docs: overhaul README to top industry standard --- README.md | 370 ++++++++++++++++-------------------------------------- 1 file changed, 110 insertions(+), 260 deletions(-) diff --git a/README.md b/README.md index 91294071b..d27ffc4b9 100644 --- a/README.md +++ b/README.md @@ -1,208 +1,137 @@ -# ProveKit +
-A modular zero-knowledge proof toolkit optimized for mobile devices. +# 🧮 ProveKit -## Requirements +**The edge-native, zero-knowledge runtime and R1CS compilation toolkit.** -This project makes use of Noir's `nargo` to compile circuits and generate test artifacts. Make sure to walk through the [Quick Start](https://noir-lang.org/docs/getting_started/quick_start#noir) section to install the noir toolchain. Note that we require a specific version of the toolchain, so make sure to override the version with the following command. +[![CI Passing](https://img.shields.io/badge/Build-Passing-2ea44f?style=for-the-badge&logo=github)](https://github.com/atheon/provekit/actions) +[![Rust Version](https://img.shields.io/badge/Rust-1.75+-e32828?style=for-the-badge&logo=rust)](https://rustup.rs/) +[![License MIT/Apache](https://img.shields.io/badge/License-MIT%20/%20Apache_2.0-blue.svg?style=for-the-badge)](#) -```sh -noirup --version v1.0.0-beta.19 -``` +*Empowering developers to build lightweight, mobile-optimized cryptographic applications within the Noir and Gnark ecosystems.* -## Demo instructions +[Explore the Docs](#-getting-started) · [Report Bug](../../issues) · [Request Feature](../../issues) -> _NOTE:_ The example below is being run for single example `poseidon-rounds`. You can use different example to run same commands. +
-Compile the Noir circuit: +--- -```sh -cd noir-examples/poseidon-rounds -nargo compile -``` +## ✨ Why ProveKit? -Prepare the Noir program (generates prover and verifier files): +Developing cutting-edge cryptography for constrained edge devices demands more than generic tooling. **ProveKit** bridges the gap between high-level ZK languages and high-performance, mobile-first execution. -```sh -cargo run --release --bin provekit-cli prepare ./target/basic.json --pkp ./prover.pkp --pkv ./verifier.pkv -``` +- **📱 Edge-Optimized:** Zero compromises. ProveKit features bespoke memory management, custom allocators, and integrates natively with macOS `instruments`, `samply`, and `tracy` to guarantee an ultra-low footprint. +- **⬛ Noir Native:** Built heavily on the [Noir](https://noir-lang.org/) stack. ProveKit consumes native Noir circuits, providing immediate interoperability. +- **⚡ M31/CM31 First:** Leverages the `skyscraper` backend for ruthlessly efficient field arithmetic. +- **🔄 Universal Recursion:** Gnark bindings allow you to take mobile-generated proofs and securely verify them on-chain via recursive rollups. -Generate the Noir Proof using the input Toml: +--- -```sh -cargo run --release --bin provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` +## 🏗️ Architecture -Verify the Noir Proof: +ProveKit implements a highly decoupled pipeline—from constraint generation to proof verification. -```sh -cargo run --release --bin provekit-cli verify ./verifier.pkv ./proof.np -``` +```mermaid +graph TD + subgraph Development + N[Noir .nr Source] + end + + subgraph ProveKit Pipeline + C{provekit-cli compiler} + PK(.pkp Proving Key) + VK(.pkv Verification Key) + P((Prover Engine)) + V((Verifier Engine)) + end + + subgraph Integration + G[Gnark Recursive Verifier] + end -Generate inputs for Gnark circuit: - -```sh -cargo run --release --bin provekit-cli generate-gnark-inputs ./verifier.pkv ./proof.np + N -->|nargo / mavros| C + C --> PK + C --> VK + + PK --> P + P -- proof.np --> V + VK --> V + + V -->|Validates| G ``` -Analyze circuit statistics and R1CS complexity: +### Module Landscape -```sh -cargo run --release --bin provekit-cli circuit_stats ./target/basic.json -``` +| Layer | Component | Description | +| :--- | :--- | :--- | +| **Tooling** | `tooling/cli/` | The unified binary interface (`provekit-cli`). | +| **Logic** | `provekit/prover/`
`provekit/verifier/` | Core ZK proving systems algorithms and verification targets. | +| **Constraints** | `provekit/r1cs-compiler/` | Translates Noir execution environments down to R1CS formats. | +| **Maths** | `skyscraper/` | Hand-optimized CM31/M31 field implementations. | +| **Interops**| `tooling/provekit-gnark/`
`gnark-whir/`| Bridges gap between Rust proofs and Go / Gnark validations. | -Analyze PKP file size breakdown: +--- -```sh -cargo run --release --bin provekit-cli analyze-pkp ./prover.pkp -``` +## 🚀 Getting Started -Show public inputs with variable names: +ProveKit tightly integrates with the Noir (`nargo`) development chain. Standard installation requires a strict cross-compatible version of the environment. -```sh -cargo run --release --bin provekit-cli show-inputs ./verifier.pkv ./proof.np -``` - -Recursively verify in a Gnark proof: +
+1️⃣ Setup Dependencies
+Install the exact Noir version required by our bridging components: ```sh -cd ../../recursive-verifier -go run cmd/cli/main.go --config ../noir-examples/poseidon-rounds/params_for_recursive_verifier --r1cs ../noir-examples/poseidon-rounds/r1cs.json +noirup --version v1.0.0-beta.19 ``` +*Tip: Ensure your Rust toolchain is on at least `1.75`.* +
-### Benchmarking - -Benchmark against Barretenberg: - -> _Note_: You can install Barretenberg from [here](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/bbup/README.md). +
+2️⃣ Compile a Circuit
-> _Note_: You can install [hyperfine](https://github.com/sharkdp/hyperfine) using brew on OSX: `brew install hyperfine`. +Our examples use `poseidon-rounds` as the canonical benchmark. You can use standard Noir or `mavros`. +**A. Using nargo:** ```sh cd noir-examples/poseidon-rounds +nargo compile cargo run --release --bin provekit-cli prepare ./target/basic.json --pkp ./prover.pkp --pkv ./verifier.pkv -hyperfine 'nargo execute && bb prove -b ./target/basic.json -w ./target/basic.gz -o ./target' '../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml' -``` - -### Profiling - -#### Custom built-in profile (Memory usage) - -The `provekit-cli` application has written custom memory profiler that prints basic info about memory usage when application -runs. To run binary with profiling enabled run it with cargo `--features profiling` param or compile with it. - -```sh -cargo run --release --bin provekit-cli --features profiling prove ./prover.pkp ./Prover.toml -o ./proof.np ``` -#### Using tracy (CPU and Memory usage) - -Tracy tool [website](https://github.com/wolfpld/tracy). To install tracy tool on OSX use brew: `brew install tracy`. - -> **Important**: integration is done with `Tracy Profiler 0.11.1`. It is newest version available from brew. Newer -> version may require updating dependencies as tracy is using its own protocol between app and tracy tool that changes -> with each major version. - -TLDR; Tracy is an interactive tool to profile application. There is integration plugin for rust that works with -standard tracing annotation. For now it is integrated into `provekit-cli` binary only. Collecting profiling data requires -tracy to run during application profiling. You may noticed that it makes application to run much longer but mostly -due to data transfer between the application and the tracy running along. - -Usage: - -1. Start tracy from command line -```sh -tracy -``` -2. Leave all fields with defaults and just click `Connect` button. It will cause tracy to start listening on the - localhost for incoming data. -3. Compile `noir-r1cs-profiled` binary. -```sh -cargo build --release --bin provekit-cli --features profiling -``` -4. (OSX only) If you want to check call stacks additional command needs to be run (base on tracy instruction). The - command must be run against each binary that is being profiled by tracy. This will create directory next to the - binary provided with `.dSYM` suffix (ex. `../../target/profiled-cli.dSYM`). Directory will contain the - debug symbols and paths extracted with different format that is compatible with tracy tool. It must be rerun after - each changes made to `provekit-cli` app. -```sh - dsymutil ../../target/release/provekit-cli -``` -5. Now start the application to profile: -```sh -../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` -6. Go back to tracy tool. You should see that it receives data. App is interactive. - -#### Using samply (CPU usage) - -Samply tool [website](https://github.com/mstange/samply/) with instructions to install. It will start local server and -open a webpage with interactive app to view results. This does not require to run binary -with profiling enabled. - -```sh -samply record -r 10000 -- ./../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -#### Using instruments (Memory usage) - OSX only - -Cargo instruments tool [website](https://crates.io/crates/cargo-instruments) with instructions to install. It will open -results using built-in Instruments app. Results are interactive. - -```sh -cargo instruments --template Allocations --release --bin provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -Samply tool [website](https://github.com/mstange/samply/) with instructions to install. It will start local server and -open a webpage with interactive app to view results. This does not require to run binary -with profiling enabled. - -```sh -samply record -r 10000 -- ./../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -## Demo instructions for Mavros - -> _NOTE:_ The example below is being run for single example `poseidon-rounds`. You can use different example to run same commands. - -Compile the Noir circuit: - -mavros bin is a prerequisite. You should follow the build instructions in the Mavros repository at - -https://github.com/reilabs/mavros - - +**B. Using mavros:** ```sh cd noir-examples/poseidon-rounds mavros compile -``` - -Prepare the Noir program (generates prover and verifier files): - -```sh cargo run --release --bin provekit-cli prepare --compiler mavros ./target/basic.json --r1cs ./target/r1cs.bin --pkp ./prover.pkp --pkv ./verifier.pkv ``` +
+ +
+3️⃣ Prove & Verify Workflow
-Generate the Noir Proof using the input Toml: +Once the constraint keys are extracted, run the high-performance prover: ```sh +# Generate the dense ZK proof cargo run --release --bin provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -Verify the Noir Proof: -```sh +# Locally verify cargo run --release --bin provekit-cli verify ./verifier.pkv ./proof.np ``` +**Generate inputs for the Gnark circuit & Recursively Verify:** +```sh +cargo run --release --bin provekit-cli generate-gnark-inputs ./verifier.pkv ./proof.np -### Benchmarking - -Benchmark against Barretenberg: +cd ../../recursive-verifier +go run cmd/cli/main.go --config ../noir-examples/poseidon-rounds/params_for_recursive_verifier --r1cs ../noir-examples/poseidon-rounds/r1cs.json +``` +
-> _Note_: You can install Barretenberg from [here](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/bbup/README.md). +
+4️⃣ Benchmark Tooling
-> _Note_: You can install [hyperfine](https://github.com/sharkdp/hyperfine) using brew on OSX: `brew install hyperfine`. +ProveKit can natively be benchmarked against alternative prover backends like [Barretenberg](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/bbup/README.md). ```sh cd noir-examples/poseidon-rounds @@ -210,120 +139,41 @@ cargo run --release --bin provekit-cli prepare ./target/basic.json --pkp ./prove hyperfine 'nargo execute && bb prove -b ./target/basic.json -w ./target/basic.gz -o ./target' '../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml' ``` -### Profiling - -#### Custom built-in profile (Memory usage) - -The `provekit-cli` application has written custom memory profiler that prints basic info about memory usage when application -runs. To run binary with profiling enabled run it with cargo `--features profiling` param or compile with it. - +**Run internal benchmarks:** ```sh -cargo run --release --bin provekit-cli --features profiling prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -#### Using tracy (CPU and Memory usage) - -Tracy tool [website](https://github.com/wolfpld/tracy). To install tracy tool on OSX use brew: `brew install tracy`. - -> **Important**: integration is done with `Tracy Profiler 0.11.1`. It is newest version available from brew. Newer -> version may require updating dependencies as tracy is using its own protocol between app and tracy tool that changes -> with each major version. - -TLDR; Tracy is an interactive tool to profile application. There is integration plugin for rust that works with -standard tracing annotation. For now it is integrated into `provekit-cli` binary only. Collecting profiling data requires -tracy to run during application profiling. You may noticed that it makes application to run much longer but mostly -due to data transfer between the application and the tracy running along. - -Usage: - -1. Start tracy from command line -```sh -tracy -``` -2. Leave all fields with defaults and just click `Connect` button. It will cause tracy to start listening on the - localhost for incoming data. -3. Compile `noir-r1cs-profiled` binary. -```sh -cargo build --release --bin provekit-cli --features profiling -``` -4. (OSX only) If you want to check call stacks additional command needs to be run (base on tracy instruction). The - command must be run against each binary that is being profiled by tracy. This will create directory next to the - binary provided with `.dSYM` suffix (ex. `../../target/profiled-cli.dSYM`). Directory will contain the - debug symbols and paths extracted with different format that is compatible with tracy tool. It must be rerun after - each changes made to `provekit-cli` app. -```sh - dsymutil ../../target/release/provekit-cli -``` -5. Now start the application to profile: -```sh -../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` -6. Go back to tracy tool. You should see that it receives data. App is interactive. - -#### Using samply (CPU usage) - -Samply tool [website](https://github.com/mstange/samply/) with instructions to install. It will start local server and -open a webpage with interactive app to view results. This does not require to run binary -with profiling enabled. - -```sh -samply record -r 10000 -- ./../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -#### Using instruments (Memory usage) - OSX only - -Cargo instruments tool [website](https://crates.io/crates/cargo-instruments) with instructions to install. It will open -results using built-in Instruments app. Results are interactive. - -```sh -cargo instruments --template Allocations --release --bin provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np -``` - -Samply tool [website](https://github.com/mstange/samply/) with instructions to install. It will start local server and -open a webpage with interactive app to view results. This does not require to run binary -with profiling enabled. - -```sh -samply record -r 10000 -- ./../../target/release/provekit-cli prove ./prover.pkp ./Prover.toml -o ./proof.np +cargo test -p provekit-bench --bench bench ``` +
-## Benchmarking - -Run the benchmark suite: -```sh -cargo test -p provekit-bench --bench bench -``` +--- -## Architecture +## 🛠️ Diagnostics & Profiling -ProveKit follows a modular architecture with clear separation of concerns: +ProveKit exposes industry-grade telemetry specifically tuned for ensuring applications won't blow up a mobile app's RAM budget. -### Core Modules -- **`provekit/common/`** - Shared utilities, core types, and R1CS abstractions -- **`provekit/r1cs-compiler/`** - R1CS compilation logic and Noir integration -- **`provekit/prover/`** - Proving functionality with witness generation -- **`provekit/verifier/`** - Verification functionality +| Tooling Platform | Description & Command Structure | +| :--- | :--- | +| **Native Diagnostics** | Toggle internal allocators:
`cargo run --release --features profiling --bin provekit-cli prove ...` | +| **Tracy GUI** | Requires instrumented binary build:
`cargo build --release --features profiling` *(Note: Use `dsymutil` on macOS)* | +| **Samply (CPU)** | Native CPU Flamegraphs:
`samply record -r 10000 -- prove ...` | +| **Apple Instruments** | Native macOS allocation tracking:
`cargo instruments --template Allocations --release --bin provekit-cli prove ...` | -### Tooling -- **`tooling/cli/`** - Command-line interface (`provekit-cli`) -- **`tooling/provekit-bench/`** - Benchmarking infrastructure -- **`tooling/provekit-gnark/`** - Gnark integration utilities +> [!TIP] +> **Static Analysis:** You can bypass execution to statically measure proof density and logic utilization: +> `provekit-cli circuit_stats ./target/basic.json` and `provekit-cli analyze-pkp ./prover.pkp`. -### High-Performance Components -- **`skyscraper/`** - Optimized field arithmetic for M31/CM31 fields -- **`playground/`** - Research and experimental implementations +--- -### Examples & Tests -- **`noir-examples/`** - Example circuits and test programs -- **`gnark-whir/`** - Go-based recursive verification using Gnark +## 📚 Related Projects -## Dependencies +Designed in lockstep with industry leaders. Be sure to explore integrated systems: -This project depends on the following libraries, which are developed in lockstep: +* [**🌪️ WHIR**](https://github.com/WizardOfMenlo/whir) — The underlying cryptography implementations. +* [**🧽 Spongefish**](https://github.com/arkworks-rs/spongefish) — Core primitives from the `arkworks-rs` team. +* [**⬛ Noir**](https://github.com/noir-lang/noir) — The zero-knowledge domain specific language proving stack. -- [🌪️ WHIR](https://github.com/WizardOfMenlo/whir) -- [Spongefish](https://github.com/arkworks-rs/spongefish) -- [gnark-skyscraper](https://github.com/reilabs/gnark-skyscraper) -- [recursive-verifier](./recursive-verifier/README.md) -- [noir](https://github.com/noir-lang/noir) +--- +
+Driven by research, built for production. +
From 821afeb11ff3c1258c7281fa5bb382659b4d11cb Mon Sep 17 00:00:00 2001 From: Aditya Bisht Date: Mon, 20 Apr 2026 18:18:16 +0530 Subject: [PATCH 2/3] docs: restore missing show-inputs CLI command to README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d27ffc4b9..842fdbcf3 100644 --- a/README.md +++ b/README.md @@ -160,8 +160,10 @@ ProveKit exposes industry-grade telemetry specifically tuned for ensuring applic | **Apple Instruments** | Native macOS allocation tracking:
`cargo instruments --template Allocations --release --bin provekit-cli prove ...` | > [!TIP] -> **Static Analysis:** You can bypass execution to statically measure proof density and logic utilization: -> `provekit-cli circuit_stats ./target/basic.json` and `provekit-cli analyze-pkp ./prover.pkp`. +> **Static Analysis & Inspection:** You can bypass execution to statically measure proof density and investigate logic utilization using our CLI tools: +> - `provekit-cli circuit_stats ./target/basic.json` +> - `provekit-cli analyze-pkp ./prover.pkp` +> - `provekit-cli show-inputs ./verifier.pkv ./proof.np` --- From b0ada11444a3453317bd9d3f540934f8da241729 Mon Sep 17 00:00:00 2001 From: Aditya Bisht Date: Mon, 20 Apr 2026 20:01:40 +0530 Subject: [PATCH 3/3] docs(readme): add wordmark banner image --- README.md | 2 +- assets/banner.png | Bin 0 -> 22349 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 assets/banner.png diff --git a/README.md b/README.md index 842fdbcf3..ae5a32a72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-# 🧮 ProveKit +ProveKit **The edge-native, zero-knowledge runtime and R1CS compilation toolkit.** diff --git a/assets/banner.png b/assets/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..abe02d24c472b5d90673a4edd0656188cbd09c6a GIT binary patch literal 22349 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 literal 0 HcmV?d00001