ByAUJay
ZK in the CI/CD Loop: Automating Proof Generation for Every Release
Short Summary
In this guide, we walk decision-makers through integrating zero-knowledge (ZK) proving into today’s CI/CD processes. By doing this, every tagged release can come with verifiable proofs. You’ll find detailed pipeline blueprints, tips on toolchain pinning, options for GPU and remote proving, caching strategies, security attestations, and insights on new practices involving Circom/snarkjs, RISC Zero, SP1, and zkSync Boojum.
Why “proofs per release” is worth doing now
In 2025, ZK transitioned from being all about research to diving into operations. There are three key changes that make it both practical and worthwhile to automate proofs in CI/CD:
- Using everyday hardware for serious proving. With zkSync’s Boojum, you can prove batches on regular consumer GPUs (just make sure they have 16 GB VRAM for the GPU provers) or CPUs. It’s super straightforward to set up in zkStack, so you can skip the “only A100s” situation and make GPU self-hosted runners a real option for a lot of teams. Check out the details here.
- Real performance from production zkVMs. Succinct’s SP1 has shown some impressive performance boosts, with zkVM improvements of 4-28 times on practical programs. For example, a ZK Tendermint light client that took 2.2 hours now runs in about 4.6 minutes! Plus, their workflow separates speedy execution from the slower proving stuff, making it perfect for CI/CD setups. Learn more here.
- Prover networks and hosted options. If you need to offload proofing, you can send them from your CI into RISC Zero’s Bonsai, which promises 99.9% uptime. Alternatively, you can go decentralized with Succinct’s Prover Network, which uses auction-based parallel proving on the mainnet. Both options help ensure you have reliable latency and SLA pathways, especially when your on-prem resources are a bit thin. More info can be found here.
The rest of this post will walk you through how to integrate ZK into your release engineering process without making every build feel like a high-performance computing (HPC) project.
What “ZK in the CI/CD loop” means
- With each release tag, we make sure to:
- Compile circuits or zkVM programs in a way that’s completely predictable.
- Generate one or more proofs using those reliable test vectors or fixture inputs.
- Verify everything locally (and, if you want, also on-chain for Groth16/PLONK verifiers).
- Attach proof artifacts like receipts, public inputs, verification keys, and signed provenance to the release.
- For every PR, we run a more budget-friendly “execution-only” or “dev-mode” route that checks for correctness without incurring the full proving costs. You’ll find SP1’s “execute only” and RISC Zero’s
RISC0_DEV_MODEare designed precisely for this. (docs.succinct.xyz)
Choose an proving path per workload
- Circuits (domain-specific constraints)
- Tooling: Check out Circom and snarkjs for Groth16 and PLONK/FFLONK. These tools let you export Solidity verifiers for those on-chain checks. You can find more details here.
- SRS considerations: If you're using KZG schemes, remember they require a trusted setup known as Powers of Tau. Treat SRS artifacts like any other regulated dependency. More info can be found here.
- zkVMs (general-purpose code in Rust/LLVM)
- RISC Zero zkVM: Think of proofs as “receipts” with a public journal and sealed proof. You can install it using
rzup, and when you're developing, just switch toRISC0_DEV_MODE. When you're ready to go live, you can flip to real proving. Bonsai has got your back with scalable remote proving. For a quick start, check it out here. - SP1 zkVM: You’ll be writing in Rust, and don’t forget to benchmark cycles during execution only in CI. When you tag a release, you can outsource proofs to the Succinct Prover Network to handle that parallelized latency. More details can be found here.
- RISC Zero zkVM: Think of proofs as “receipts” with a public journal and sealed proof. You can install it using
- High-throughput rollups
- zkSync Boojum: If you’re planning on using GPU or CPU proving boxes, make sure your GPU has at least 16 GB VRAM. You can get started with
zkstack prover init/runwhen transitioning from dummy to real proofs. Just keep an eye on your runner specs and budget accordingly. For further information, click here.
- zkSync Boojum: If you’re planning on using GPU or CPU proving boxes, make sure your GPU has at least 16 GB VRAM. You can get started with
CI/CD blueprint: end‑to‑end
The patterns listed below have been production-hardened at 7Block Labs, using both GitHub Actions and GitLab CI.
1) Reproducible toolchains
- Pin versions:
- For Circom/snarkjs, make sure to lock the npm versions and save the selected
.ptauhash along with the source URL. - For RISC Zero, pin the
rzupchannel/release andcargo-risczero; check that the ImageID remains constant across builds. You can find more info at (dev.risczero.com). - For SP1, don’t forget to pin the Rust toolchain (make sure MSRV is ≥1.79) and the versions of the SP1 crates. More details can be found on (github.com).
- For Circom/snarkjs, make sure to lock the npm versions and save the selected
- Cache compiles:
- For Rust, use
Swatinem/rust-cachefor both host and guest crates in your matrix builds. Check it out on (github.com). - For General artifacts, leverage
actions/cache@v4to cachetarget/,.wasm,.zkey, and.ptaufiles, using a hash of the circuit and tool versions as the key. More info is available at (github.com).
- For Rust, use
2) Witness and proof generation
- Circom/snarkjs (Groth16 example)
- Start by compiling and computing the witness. You only need to run the setup once for each circuit, then generate the proof and verify it. Don’t forget to export the verifier for Solidity!
- The CLI is pretty stable and can be scripted for CI. Check out the details in the docs.
- RISC Zero
- For PRs, kick off the host binary with
RISC0_DEV_MODE=1(it’s speedy!), and switch to=0for releases to get the real receipts. Make sure to publish those receipts and journals as artifacts. You can find more info at dev.risczero.com.
- For PRs, kick off the host binary with
- SP1
- During PRs, just run “execution only” and keep track of the cycle counts. For releases, you’ll want to call the prover network or GPU cluster for those proofs. More guidelines are available in the docs.
3) GPU vs remote proving
- Self-hosted GPU runners
- If you're using GitLab SaaS, you can easily access GPU-enabled runners by tagging them. Just choose a CUDA image and run
nvidia-smito confirm everything's set up. Check out the details in the GitLab documentation.
- If you're using GitLab SaaS, you can easily access GPU-enabled runners by tagging them. Just choose a CUDA image and run
- Remote proving
- Take a look at RISC Zero Bonsai for some cool API-driven proving. It's got an uptime target and some neat recursive/composition features tucked away behind the zkVM. You can find more info here.
- The Succinct Prover Network is live on the mainnet, allowing you to parallelize large tasks. Expect some auction-based pricing and staking for provers. Get the scoop here.
4) Attestations and provenance
- Create signed build provenance for proof artifacts by leveraging GitHub’s
actions/attest-build-provenance(which issues a Sigstore certificate and includes the in-toto SLSA predicate). Make sure to enforce this in your clusters using the Sigstore Policy Controller. You can check it out here.
Concrete pipeline examples (copy‑paste friendly)
A. GitHub Actions: Circom + snarkjs (Groth16) with cached SRS
name: zk-circuits
on:
push:
tags: ["v*"]
pull_request:
jobs:
groth16:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install circom + snarkjs
run: |
npm i -g circom@2 snarkjs@0.7.4
- name: Cache SRS and artifacts
uses: actions/cache@v4
with:
path: |
./.zk/ptau
./artifacts
key: ${{ runner.os }}-circom-${{ hashFiles('circuits/**/*.circom') }}-snarkjs-0.7.4
restore-keys: |
${{ runner.os }}-circom-
- name: Ensure ptau (Powers of Tau) present
run: |
mkdir -p .zk/ptau
test -f .zk/ptau/powersOfTau28_hez_final_17.ptau || \
curl -L -o .zk/ptau/powersOfTau28_hez_final_17.ptau \
https://hermezptau.s3.eu-central-1.amazonaws.com/powersOfTau28_hez_final_17.ptau
- name: Compile circuit
run: |
mkdir -p artifacts
circom circuits/multiplier.circom --r1cs --wasm --sym -o artifacts
- name: Compute witness
run: |
node artifacts/multiplier_js/generate_witness.js \
artifacts/multiplier_js/multiplier.wasm inputs/input.json \
artifacts/witness.wtns
- name: Groth16 setup (idempotent)
run: |
test -f artifacts/multiplier_0001.zkey || (
snarkjs groth16 setup artifacts/multiplier.r1cs \
.zk/ptau/powersOfTau28_hez_final_17.ptau artifacts/multiplier_0000.zkey
snarkjs zkey contribute artifacts/multiplier_0000.zkey \
artifacts/multiplier_0001.zkey -e="dev-beacon"
)
- name: Prove and verify
run: |
snarkjs groth16 prove artifacts/multiplier_0001.zkey artifacts/witness.wtns \
artifacts/proof.json artifacts/public.json
snarkjs groth16 verify artifacts/verification_key.json \
artifacts/public.json artifacts/proof.json
# See Circom/snarkjs docs for exact commands and semantics.
This follows the established snarkjs flow (compile → witness → setup → prove → verify), which works great for CI scripting. You can export verifier.sol on release tags and either attach it to the repo or deploy it using Hardhat. Check out the details here: (docs.circom.io)
- name: Export Solidity verifier (release only)
if: startsWith(github.ref, 'refs/tags/')
run: |
snarkjs zkey export solidityverifier artifacts/multiplier_0001.zkey \
contracts/Verifier.sol
Tip: When you’re using hardhat-circom, this plugin is super handy because it creates verifiers and even has a built-in deterministic Groth16 beacon for your development builds. This helps cut down on the churn of .zkey files. Just a heads up--don’t send those deterministic beacons to production. Check it out on GitHub!
B. GitHub Actions: RISC Zero zkVM receipts with reproducible ImageID
name: risc0-proofs
on:
push:
tags: ["v*"]
pull_request:
jobs:
zkvm:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install RISC Zero toolchain
run: |
curl -L https://risczero.com/install | bash
~/.rzup/bin/rzup # installs toolchain and cargo-risczero
- name: Build guest + host and print ImageIDs
run: |
cargo risczero build --manifest-path guest/Cargo.toml
rustup toolchain list | grep risc0 || true
- name: Fast checks (PRs) with dev-mode
if: github.event_name == 'pull_request'
env:
RISC0_DEV_MODE: "1"
run: cargo run --release -p host
- name: Generate real proof (tags)
if: startsWith(github.ref, 'refs/tags/')
env:
RISC0_DEV_MODE: "0"
run: cargo run --release -p host -- --out artifacts/receipt.cbor
- name: Verify receipt and publish artifacts
if: startsWith(github.ref, 'refs/tags/')
run: |
cargo test -p verifier
mkdir -p artifacts && cp -v target/**/*.id artifacts/ || true
# Verifier crate confirms receipt against ImageID and journal.
This is based on RISC Zero’s quickstart/dev-mode guidance along with the receipt/journal model. If you want, you can replace the local “real proof” step with a call to the Bonsai API, which will handle the heavy lifting of proving for you. Check it out here: (dev.risczero.com)
C. GitLab CI: GPU‑enabled jobs (for Boojum or heavy zkVM proving)
stages: [build, prove]
prove-gpu:
stage: prove
tags: [saas-linux-medium-amd64-gpu-standard] # GitLab SaaS GPU runner
image: nvcr.io/nvidia/cuda:12.1.1-base-ubuntu22.04
script:
- nvidia-smi
- ./scripts/prove.sh
GitLab lets you use the GPU for your job by mounting it right in. Just pick a CUDA image and check your access with nvidia-smi. This setup is perfect for Boojum prover nodes or for those GPU-accelerated proof steps. You can get more details here.
Build outputs you should publish on every release
For the proving system, don’t forget to attach these to your GitHub or GitLab releases:
- Circom/snarkjs
- You'll find
proof.json,public.json, andverification_key.jsonhere. - Check out the
.zkeyfile, which is the final version that includes contributions, plus the.r1cshash. - Don’t forget
verifier.sol, or if it’s already been deployed, the address along with the template commit.
- You'll find
- RISC Zero
- Keep an eye out for the receipt file (like CBOR), the journal in JSON format, and a list of ImageID(s).
- You’ll also want the SHAs for the host/guest crate and the version of
rzup/toolchain.
- SP1
- This includes the proof artifact, the public values, and the crate SHAs.
- Also, you’ll find the cycle counts from execution-only benchmarking.
Next up, let’s create signed provenance for all the proof artifacts:
- uses: actions/attest-build-provenance@v3
with:
subject-path: 'artifacts/**'
This creates Sigstore-signed in-toto/SLSA attestations and sends them over to GitHub’s Attestations API. If you're shipping containers that include verifiers, make sure to enforce these at deployment time using a Kubernetes policy controller. For more info, check out the GitHub page.
Performance and cost controls that matter in CI
- Split “execution” vs “proof” phases:
- For PRs, you can run a quick execution-only test (SP1) or set
RISC0_DEV_MODE=1to check the logic and public outputs. - When it comes to releases, run the proofs once and then cache those artifacts for efficiency. Check out the details here.
- For PRs, you can run a quick execution-only test (SP1) or set
- Cache aggressively:
- Use
actions/cache@v4to cache files like.ptau,.zkey,.wasm, and thetarget/directory. - For Rust builds, implement
Swatinem/rust-cache@v2. You can find more info on this GitHub page.
- Use
- GPU provisioning:
- If you're dealing with Boojum’s low-TPS scenarios, make sure to plan for at least 16 GB of VRAM on the GPU side or go for 32-128 cores with 64-128 GB of RAM on the CPU side. Scale your runner size to fit your target batch sizes. More details can be found here.
- Remote burst:
- If your proofs go over the CI time budget, you might want to offload them to Bonsai or the Succinct Prover Network. Block the release until you get a callback or webhook. This way, the network can handle proving in parallel, rather than putting all the pressure on a single GPU. Check it out here.
- Timeouts and retries:
- For hosted runners, it's wise to set a maximum runtime for each job. Adopting a “local → remote fallback” approach can save you from those frustrating stuck releases.
Security, compliance, and governance
- Attestations + Policy
- Use signed provenance through
actions/attest-build-provenance(these are Sigstore short-lived certs) and make sure to enforce this with cluster admission policies. Check it out here: (github.com)
- Use signed provenance through
- Reproducibility
- For RISC Zero, make sure to reproduce the ImageID straight from the source. Your verifier should check the receipt against that ImageID and journal. It’s a good idea to treat the ImageID as a top-tier artifact in your releases. More info can be found here: (dev.risczero.com)
- SRS Lifecycle (Circom/KZG)
- Handle
.ptaufiles and ceremony transcripts like they’re vital third-party cryptographic dependencies. Always keep track of explicit provenance and hashes. Don’t forget to cite the ceremony source and version in your release notes. Get all the details here: (plonkbook.org)
- Handle
Advanced: aggregation and recursion strategy in 2025
If the costs of verification or proof fan-out start to increase, it’s a good idea to think about implementing folding or aggregation:
- The folding systems, like Nova, SuperNova, and HyperNova, are pretty cool because they turn lengthy computations into compact verifiers. Plus, MicroNova and HyperKZG are all about boosting on-chain efficiency. These tools are becoming more user-friendly, but just a heads up--keep an eye on the changing security aspects and the choices you make for parameters. (github.com)
- A little security reminder: there are several papers out there that take a closer look at different Nova variants, focusing on things like cycles of curves and bounded recursion assumptions. If you’re planning to roll out folding in a production setting, make sure you monitor the specific instantiation and security claims. And don't forget to pin your versions in CI to keep everything aligned. (eprint.iacr.org)
- On the topic of Plonky2 and aggregation architectures (like ZKM), they showcase some really neat multi-stage aggregation stacks for Plonkish tables. This setup is super handy when you’ve got a bunch of micro-proofs being generated for each commit. (zkm.io)
Emerging best practices we’re applying for clients
- Circuit semantics versioning
- Let's stick to semver for our circuits and zkVM programs. Any breaking changes will bump the MAJOR version, and changes to
verifier.solor ImageID are considered release-blocking events.
- Let's stick to semver for our circuits and zkVM programs. Any breaking changes will bump the MAJOR version, and changes to
- Proof budgets
- We're going to set some target SLAs: “<15 min wall-clock proving per release on N×L4 GPUs” or we'll have a fixed spending cap through a prover network. Check out the details here.
- Dual‑path proving
- We’ll maintain both a “local GPU” path for quick feedback and a “remote prover” path for scalability and SLA purposes. You can choose between them using environment flags in the same pipeline.
- Deterministic dev builds
- For Groth16 development iterations, let’s use deterministic beacons via
hardhat-circomto keep zkey churn to a minimum. Just remember, don’t send those beacons to production. You can find it on GitHub.
- For Groth16 development iterations, let’s use deterministic beacons via
- On‑chain sanity checks in CI
- For Groth16/PLONK, we should spin up a local EVM and call
verifyProofwith the CI-generated calldata before we deploy. This way, we can catch any ABI ordering issues or regressions before hitting mainnet. More info is available here.
- For Groth16/PLONK, we should spin up a local EVM and call
A “release checklist” you can adopt tomorrow
- Toolchains pinned:
- Versions for circom/snarkjs and the
.ptauhash are locked in. - We're using the RISC Zero toolchain with the
rzuptag, and I've made a note of the ImageID. - The SP1 crate versions and Rust MSRV are also pinned down.
- Versions for circom/snarkjs and the
- Proofs generated:
- For Circom, I've got the r1cs hash, zkey, proof/public, and verifier.sol all exported.
- RISC Zero proofs? Check! The receipt and journal are verified against the ImageID.
- SP1 has generated proof along with public values, and I’ve logged the cycles.
- Artifacts attached:
- Everything's here: proofs plus public inputs.
- Verification keys or the verifiers, and the deployed address, are included.
- All artifacts have their attestations (Sigstore/SLSA) attached.
- Gates passed:
- Local verification steps are all green, which is great news!
- Optional on-chain local EVM verification tests have passed as well.
- We've kept the time and costs within budget or offloaded them as per the policy.
Putting it together: one pipeline to rule them all
- PRs
- For Circom/snarkjs: Just compile and create the witness; let’s skip the full Groth16 if nothing's changed.
- RISC Zero: Run it with
RISC0_DEV_MODE=1. - SP1: Only execute and get a cycles report.
- Tags
- With Circom/snarkjs: We need to create the full proof, export the verifier, and then verify it in the local EVM.
- For RISC Zero: Make sure to generate the full receipt, verify it, and attach the ImageID map.
- SP1: Send it off to the prover network, and release the block when the webhook triggers.
- Don’t forget to attest the artifacts and publish them!
This method allows your organization to deliver cryptographically verifiable releases without needing to turn every developer's machine into a prover.
Where we see the space heading (next 12 months)
- Lower device floors: With Boojum-class GPU minima, "ZK runners" are becoming the go-to standard for CI resources instead of just being reserved for special projects. Check it out here.
- Networked proving as default: Now that Succinct’s mainnet prover network is up and running, more teams are starting to see proving as just another workload to manage, rather than a specific machine they need to own. Dive into the details here.
- zkVM maturity: Thanks to SP1’s fast speeds and reliable workflows, more teams are coming together to unify circuit logic in Rust. This way, they can let the VM handle the heavy lifting, especially when it comes to complex, branching logic. For more insights, head over here.
7Block Labs can help
We’re all about designing, building, and securing ZK CI/CD for both startups and big businesses. Whether you’re picking out proving stacks, connecting GPU/remote provers, managing versioning for SRS, writing up verifiers, or making sure attestations are solid, we’ve got you covered. If your goal is to have “every release ships with proofs,” we’ll ensure it gets done quickly and without all the drama.
Sources and further reading
- Check out the circom/snarkjs proving and Solidity verifier export commands and flow over at the Circom Docs.
- If you're diving into zkSync, don’t miss the Boojum prover requirements and how to enable it using zkStack. You can find all the info in the zkSync Docs.
- For a quick start with RISC Zero, take a look at
rzup, receipts/journal, and the differences between dev-mode and real proving. Plus, there's a neat overview of Bonsai too! Head over to the RISC Zero Dev Docs for that. - Get the lowdown on Succinct SP1 performance and the best workflow to follow. They also provide some context about the Prover Network. Check it out on the Succinct Blog.
- Curious about Halo2 IPA? They have a solid background on it along with the KZG SRS. Just dive into the details on the Zcash GitHub.
- Lastly, if you're using GitLab, you might want to learn about using the GPU runner and how GitHub handles artifact attestations and provenance. All that info is in the GitLab Docs.
Like what you're reading? Let's build together.
Get a free 30-minute consultation with our engineering team.
Related Posts
ByAUJay
Building 'Private Social Networks' with Onchain Keys
Creating Private Social Networks with Onchain Keys
ByAUJay
Tokenizing Intellectual Property for AI Models: A Simple Guide
## How to Tokenize “Intellectual Property” for AI Models ### Summary: A lot of AI teams struggle to show what their models have been trained on or what licenses they comply with. With the EU AI Act set to kick in by 2026 and new publisher standards like RSL 1.0 making things more transparent, it's becoming more crucial than ever to get this right.
ByAUJay
Creating 'Meme-Utility' Hybrids on Solana: A Simple Guide
## How to Create “Meme‑Utility” Hybrids on Solana Dive into this handy guide on how to blend Solana’s Token‑2022 extensions, Actions/Blinks, Jito bundles, and ZK compression. We’ll show you how to launch a meme coin that’s not just fun but also packs a punch with real utility, slashes distribution costs, and gets you a solid go-to-market strategy.

