Why zero‑knowledge proofs for ML are worth your time
Most machine learning systems ask you to trust the model owner, the API, and the infrastructure. That breaks down in real situations: you want to check a vendor’s answer without giving them your data; you want to reward creators per inference without seeing their inputs; or you want to gate actions on‑chain using a prediction without rebuilding the model inside a smart contract. Zero‑knowledge machine learning (ZKML) gives you a new knob to turn: prove that “the model M with commitment C, when run on input x committed as D, produced output y” without revealing x or M. A verifier learns only what you choose to make public, plus a short, math‑backed proof that the computation was done correctly.
Until recently, this sounded academic. It is now becoming practical for small models, tiny graphs, and selective checks. You won’t be proving GPT‑level inferences any time soon, but you can already ship real products around compact neural nets and scoring models.
- Privacy: Prove a risk score above a threshold without showing the underlying features.
- Integrity: Verify that a marketplace ran your model with the exact weights you supplied.
- Portability: Check computations off‑chain and on‑chain with the same proof artifact.
- Attribution and billing: Pay‑per‑inference with confidence that the right function was executed once.
How a proof of inference actually works
From model to arithmetic circuit
Zero‑knowledge proof systems don’t speak Python or floating‑point math. They check statements in arithmetic form—typically constraints over a finite field. To prove an ML inference, you must convert your model graph into a circuit the proof system can validate:
- Quantize and fix precision: Map floats to fixed‑point integers, e.g., 16‑bit or 8‑bit with a shared scale. You trade tiny accuracy loss for far lower proof cost.
- Choose friendly ops: Linear layers (conv, matmul), additions, and piecewise‑linear activations like ReLU are ZK‑friendly. Smooth nonlinearities (sigmoid, tanh) need approximations or lookup tables.
- Express constraints: Each operation becomes a set of polynomial constraints. Systems like Halo2 and STARK variants bundle constraints efficiently, use lookup arguments, and reuse patterns for common layers.
The witness is the private transcript that contains inputs, intermediate activations, and outputs. The prover uses the witness and the circuit to compute a short proof. The verifier checks the proof against public commitments—for example, a hash of the weights and selected public outputs—without seeing the witness itself.
What’s public, what stays private
You decide which elements are public:
- Public model commitment: A hash of the weights ensures the proof binds to an exact version of the model.
- Public output: Sometimes you want the output visible (e.g., a number or class label) plus the proof that it came from the right model.
- Hidden input: Inputs can remain secret (e.g., personal features, sensor traces). The proof shows the relation holds without exposing them.
- Hidden output with a property: You can also keep the output private but prove a property of it (e.g., “score ≥ 0.7”). This needs constraint logic in the circuit to encode the property.
Proof systems in brief: SNARKs, STARKs, and zkVMs
Several proof families power ZKML. You don’t need to become a cryptographer, but a mental map helps:
- SNARKs: Short proofs, fast verification, small on‑chain cost. Many require a trusted setup (Groth16) or use universal setups (PLONK, Halo2). Great for fixed circuits. Widely supported.
- STARKs: Transparent (no trusted setup), scalable, often faster for large circuits. Proofs are bigger but compress well; verification is still fast. Popular for rollups and big computations.
- zkVMs: Instead of hand‑building circuits, run code inside a zero‑knowledge virtual machine (RISC‑V, WASM). More flexible; proof cost is higher than bespoke circuits but easier to program and maintain.
Most practical ZKML stacks use prebuilt circuits for common ML layers or compile ONNX graphs into circuits. zkVMs are compelling when your pipeline includes pre‑ and post‑processing logic that would otherwise be a pain to circuit‑encode.
Where ZKML makes sense today
- Selective disclosure: Employment, age, or region checks based on a face or document scan without revealing the scan or exact score.
- On‑chain games and markets: Agents or bots take actions based on model outputs proven off‑chain; smart contracts accept only results with valid proofs.
- Model marketplaces: Creators sell inference access; buyers verify that a specific weight set produced a prediction the seller claims.
- Data sharing with audit: Two firms co‑score candidates with a shared model but never share raw features. Each proves its partial computation and aggregates the result.
Notice what’s not on this list: huge language models, diffusion pipelines, or high‑throughput streaming analytics. Those are far beyond current proof budgets. Focus on compact models with stable, low‑entropy inputs and narrow outputs.
Tooling you can try (and what it’s good for)
ezkl (Halo2 circuits)
ezkl compiles ONNX models into Halo2 circuits, supports quantization, and comes with relayers and Ethereum verifiers. It’s a good first stop if your model is mostly linear layers and ReLU/MaxPool. You get a CLI to generate witnesses and proofs and sample Solidity contracts to verify them.
RISC Zero (zkVM for RISC‑V)
RISC Zero lets you write normal Rust programs that run inside a ZK RISC‑V machine. It’s great when your pipeline includes preprocessing (tokenization, normalization) and you want to avoid custom circuits. The cost per instruction is higher than a specialized circuit, but development time is lower. They also provide cloud‑accelerated proving flows.
STARK‑based stacks
Frameworks building on STARKs (such as StarkWare’s tools and ecosystems around StarkNet) are evolving with ML‑friendly primitives and lookup arguments that can handle activation functions with table checks. If you’re targeting a STARK‑based chain or want transparent proofs, this route is promising.
Other pieces you will meet
- snarkjs / circom: Mature stack for Groth16 and PLONK circuits. Good for handcrafted flows and learning the ropes.
- zkWASM / zkSync Boojum: zkVM flavors oriented around WASM or custom provers. Useful when you prefer to code in high‑level languages and compile down.
- Modulus Labs and similar teams: Research and examples focused on proving small neural nets for games and agents. Helpful for patterns and circuit strategies.
A minimal end‑to‑end pilot you can ship
1) Scope something the math can finish
Pick a binary classifier or small convnet that takes fewer than 1M multiply‑accumulate operations for a single inference. For a pilot, think tiny image classifier, compact tabular risk model, or keyword spotter. Your product value should come from the guarantee, not raw accuracy.
2) Train and quantize
- Train in PyTorch or TensorFlow with quantization‑aware training if possible. Post‑training int8 quantization also works for many models.
- Freeze batchnorm (fold into conv weights), prefer ReLU over sigmoid/tanh, and avoid dynamic control flow.
- Export to ONNX. Validate accuracy drop from quantization (aim for less than 1–2% absolute).
3) Compile to a circuit
- Use ezkl to import your ONNX graph. Configure fixed‑point scales per layer or globally. Watch for overflow: your integer ranges must comfortably hold intermediate activations.
- Mark public and private signals. At minimum, make the model commitment public by hashing the weights and exposing the hash in the circuit.
- Generate a witness from a sample input. This step often finds shape mismatches and stray ops not supported in your stack.
4) Prove and verify locally
- Produce a proof using your chosen backend (Halo2, PLONKish, STARK). Time it and watch memory—proving can be heavy.
- Verify the proof on your laptop. Verification should be milliseconds to low seconds, even for non‑trivial circuits.
5) Add a verifier where it matters
- Off‑chain: Wrap verification in your API so partners can check results programmatically before accepting them.
- On‑chain: Deploy a Solidity verifier if you need smart contracts to check outputs. Groth16 is cheap to verify; PLONK and STARK verifiers are improving quickly. Consider proof aggregation to reduce gas.
6) Bind to versioning and terms
- Include the weight hash, the ONNX graph hash, and a policy identifier as public constants. Now “what exactly did we prove?” is unambiguous.
- Log the same IDs in your product analytics and invoices. Tie payments to proof acceptance.
7) Automate
- Build CI jobs that re‑compile the circuit on model updates, run regression checks (accuracy delta, proof timing), and refuse deploys if constraints drift.
- Keep a small test corpus to sanity‑check both inference results and proof soundness on every build.
Performance, cost, and scale: what to expect
Proving time and memory
Proving dominates your budget. Expect seconds to minutes for small CNNs on a workstation‑class machine, more for laptops. Memory spikes can be significant during witness generation and polynomial I/O. GPU‑accelerated provers, lookup arguments, and circuit‑friendly quantization all help. Measure on the hardware you intend to run in production, not in a one‑off lab build.
Verification time and placement
Verification is typically sub‑second on modern CPUs and practical on smart contracts designed with verifier precompiles. When integrating with blockchains, the choice of proof system affects gas cost dramatically. If you just need business‑to‑business verification, keep it off‑chain and sign the verified outputs to avoid on‑chain cost entirely.
Techniques to cut cost
- Smaller bit‑width: Int8 is standard; some stacks support 4‑bit for certain layers if accuracy holds.
- Operator fusion: Combine adjacent linear operations before circuitization to save gates.
- Sparsity: Prune weights and exploit structured sparsity where your circuit or zkVM can skip zeros.
- Lookups for activations: Use table constraints for ReLU or bounded nonlinearities instead of bespoke polynomials.
- Recursion and aggregation: Prove layer chunks separately, then aggregate into a single top‑level proof.
Security and correctness gotchas
Floating‑point ghosts
Your reference model runs in floats; the circuit runs in integers. Mismatches appear when scale factors or rounding modes drift. Fix this by locking scales per layer and using a single, well‑tested quantization library for both training and export. Always keep test vectors that compare float outputs and fixed‑point outputs under the same inputs.
Unintended information leakage
Check that public values do not reveal sensitive input ranges indirectly. For example, publishing all logits instead of only the class index can leak more than necessary. Prefer proving threshold relations (“score ≥ t”) instead of dumping the whole output vector.
Binding to the right thing
Commit to the exact weight array and the exact graph description. If your pipeline applies preprocessing (e.g., normalization), consider moving it inside the circuit or zkVM so the proof covers it. Otherwise, you’re proving the wrong function.
Non‑determinism and randomness
Randomized layers, dropout, and any external sources of randomness must be removed or seeded inside the circuit. ZK proof statements must be deterministic—every valid witness leads to the same output given the same public inputs.
Privacy patterns you can ship
Threshold proofs
Instead of revealing a risk score, prove it exceeds (or stays below) a threshold. This requires range checks on the fixed‑point output and is friendly to existing circuits.
Equality and set membership
Prove that an embedding lies in a cluster without revealing the exact vector. You can hash a coarse code or use a Merkle inclusion proof for a pre‑approved set of codes and tie it to the model commitment.
Selective reveal
Publish the class label but hide confidence. Or reveal top‑1 and a calibrated “safe to act” flag, both proven from the same witness. Design your API so consumers can ask for the minimum they need to decide.
Combining ZK with confidential computing
Trusted execution environments (TEEs) and confidential VMs run your model in encrypted memory and attest to code identity. They are fast but rely on hardware trust and supply‑chain assumptions. ZK proofs are pure math, slower, and do not need hardware trust. The two can work together:
- Run heavy inference inside a TEE; generate a compact ZK proof of just the critical property you need to publish.
- Use a TEE to keep keys and rate‑limiters safe while ZKML handles public verification of outputs.
- Fall back to TEE‑only mode when proof queues are saturated; flag results as “attested only” vs “ZK‑verified.”
This hybrid approach lets you iterate now and add ZK guarantees to the most sensitive or high‑value flows first.
Governance, UX, and operations
Explain the guarantee in one sentence
Users and partners don’t care about polynomial commitments. They care about what they can rely on. Put a short line near every verified result: “This result was produced by model X (hash …) from hidden inputs, with a zero‑knowledge proof checked on Y.” Link to a human‑readable page with details.
Rotate models without breaking everything
Publish a version map: model name → weight hash → graph hash → date. Allow multiple model commitments during a grace period. Deprecate with clear cutoffs and automated alerts when clients submit proofs for sunsetted versions.
Metering and SLAs
Prover time is variable. Keep queues visible. Offer two lanes: fast, attested‑only; slower, ZK‑verified. When ZK proofs are required, communicate expected completion windows and partial updates (“proof created”, “queued for verification”, “verified”).
Roadmap: what’s improving fast
- Lookup‑heavy circuits: Better table techniques make non‑linear activations cheaper.
- GPU and ASIC provers: Dedicated acceleration is shrinking proving time by orders of magnitude for common circuits.
- zkVM ergonomics: More mature libraries for fixed‑point math and ML primitives inside zkVMs reduce custom circuit work.
- Aggregation and recursion: Multi‑proof rollups and recursive SNARKs make batch verification cheaper on‑chain.
- Model‑aware compilers: Direct compilation from ONNX/TVM to constraints with auto‑fused ops and scale inference is arriving.
Concrete use cases to pilot
Private eligibility checks
An NGO runs a compact classifier on household survey data to prioritize aid. Families submit encrypted inputs and receive a proof that “eligibility score ≥ threshold T” without exposing the raw answers. Field partners verify proofs on mobile devices before delivering aid.
On‑chain model marketplaces
A creator publishes a tiny defect‑detection CNN for specific parts. Manufacturers upload images privately, get back the decision and a proof bound to the creator’s weight hash, pay per accepted proof, and never share source images.
Bring‑your‑own‑model for scoring
A fintech lets enterprise customers upload their own small tabular models. The platform runs inferences and posts proofs to a shared audit log. Downstream lenders verify proofs before funding loans, with no access to applicants’ features.
Troubleshooting checklist
- Accuracy collapsed after circuitization? Check fixed‑point scales, fold batchnorm, and ensure ReLUs are implemented as lookups not polynomials that clip.
- Proof time exploded? Count MACs, prune, and consider reducing bit‑width. Try a prover with GPU support.
- Verifier rejects sporadically? Mismatched model or graph hashes, or nondeterminism in preprocessing. Bring preprocessing inside the proof.
- On‑chain gas too high? Switch to Groth16 for fixed circuits, use aggregation, or verify off‑chain and anchor only a succinct receipt on‑chain.
Summary:
- ZKML lets you prove an ML inference was computed correctly without revealing inputs or weights.
- It’s practical today for small models with ZK‑friendly ops, fixed‑point math, and clean preprocessing.
- Start with tools like ezkl (Halo2) or a zkVM (RISC Zero) and bind proofs to exact model and graph hashes.
- Focus on selective disclosure: threshold proofs, minimal outputs, and strict public/private signal design.
- Expect proving to dominate cost; cut it with quantization, fusion, sparsity, lookups, and aggregation.
- Combine with confidential computing for speed now, add ZK guarantees where they matter most.
- Communicate the guarantee in plain language, version models cleanly, and automate regression checks.
