EZKL — Zero-Knowledge Proofs for ML Models
EZKL converts any ONNX-formatted ML model into a ZK-SNARK circuit, enabling cryptographic verification that a model ran correctly on specific inputs without revealing private data. Written in Rust with Python, JavaScript/TypeScript (WASM), and CLI interfaces. Generates EVM-compatible Solidity verifier contracts for on-chain verification.
When to Use This Skill
- Converting ML models to ZK circuits
- Generating and verifying proofs of ML inference
- Deploying on-chain verifiers for model outputs
- Working with
@ezkljs/engine(JS/TS SDK) orezkl(Python/CLI) - Integrating zkML into applications (Node.js, Bun, browser, EVM chains)
Core Workflow — 9 Steps
Every EZKL pipeline follows this sequence regardless of interface (CLI, Python, JS):
| Step | Purpose | Output File |
|------|---------|-------------|
| 1. Export model | PyTorch/TF/sklearn to ONNX | model.onnx |
| 2. Generate settings | Circuit configuration | settings.json |
| 3. Calibrate (optional) | Optimize accuracy or resources | settings.json (updated) |
| 4. Compile circuit | ONNX to ZK circuit | network.ezkl |
| 5. Get SRS | Cryptographic reference string | kzg.srs |
| 6. Setup (key gen) | Generate proving/verification keys | pk.key, vk.key |
| 7. Generate witness | Record all intermediate values | witness.json |
| 8. Prove | Generate the ZK proof | proof.json |
| 9. Verify | Check proof validity | boolean |
Verification requires only: proof.json, vk.key, settings.json, kzg.srs — no model weights or private inputs.
Key Concepts
Settings (settings.json): Circuit configuration controlling visibility (public/private/hashed), quantization scale, circuit size (logrows), and commitment scheme (KZG or IPA). Generated by gen_settings, tuned by calibrate_settings.
Visibility options: public | private | fixed | hashed/public | hashed/private | polycommit — applied independently to inputs, outputs, and model parameters.
Quantization: EZKL quantizes floating-point values to fixed-point field elements. Minor output discrepancies vs standard inference are expected. Control with tolerance in settings.
Circuit size: logrows = log2 of circuit rows. Non-linear ops (ReLU, sigmoid, GELU) require lookup tables and significantly increase circuit size and proving time.
SRS: Structured Reference String for KZG commitments. Fetched from EZKL servers via get-srs or self-generated. Size depends on logrows.
Installation
# JavaScript/TypeScript SDK
bun add @ezkljs/engine
# Python bindings (includes CLI)
pip install ezkl
# CLI only (Rust binary)
curl https://raw.githubusercontent.com/zkonduit/ezkl/main/install_ezkl_cli.sh | bash
JavaScript/TypeScript SDK (@ezkljs/engine)
Two build targets:
@ezkljs/engine/nodejs— Node.js/Bun (no web workers)@ezkljs/engine/web— Browser with SharedArrayBuffer (requires COOP/COEP headers)
Node.js/Bun Quick Start
import { readFileSync } from 'fs';
import { genWitness, prove, verify, serialize, deserialize } from '@ezkljs/engine/nodejs';
const compiledModel = readFileSync('./network.ezkl');
const pk = readFileSync('./pk.key');
const vk = readFileSync('./vk.key');
const srs = readFileSync('./kzg.srs');
const input = serialize({ input_data: [[1.0, 2.0, 3.0, 4.0]] });
const witnessBuffer = genWitness(compiledModel, input);
const proofBuffer = prove(witnessBuffer, pk, compiledModel, srs);
const isValid = verify(proofBuffer, vk); // true
Core JS Functions
genWitness(compiledModel: Uint8Array, input: Uint8Array): Uint8Array
prove(witness: Uint8Array, pk: Uint8Array, compiledModel: Uint8Array, srs: Uint8Array): Uint8Array
verify(proof: Uint8Array, vk: Uint8Array): boolean
poseidonHash(message: Uint8Array[]): string[]
serialize(artifact: object): Uint8Array
deserialize(buffer: Uint8Array): object
Browser Initialization
import init from '@ezkljs/engine/web/ezkl.js';
await init(undefined, new WebAssembly.Memory({
initial: 20, maximum: 4096, shared: true // max 4096 for iOS
}));
Required headers: Cross-Origin-Embedder-Policy: require-corp and Cross-Origin-Opener-Policy: same-origin.
CLI Quick Reference
ezkl gen-settings --model model.onnx --output settings.json
ezkl calibrate-settings --data input.json --model model.onnx --settings settings.json --target accuracy
ezkl compile-circuit --model model.onnx --compiled-circuit network.ezkl --settings-path settings.json
ezkl get-srs --settings-path settings.json --srs-path kzg.srs
ezkl setup --model network.ezkl --vk-path vk.key --pk-path pk.key --srs-path kzg.srs
ezkl gen-witness --data input.json --model network.ezkl --output witness.json
ezkl prove --witness witness.json --model network.ezkl --pk-path pk.key --proof-path proof.json
ezkl verify --proof-path proof.json --settings-path settings.json --vk-path vk.key --srs-path kzg.srs
ezkl mock --witness witness.json --model network.ezkl # fast sanity check
ezkl table --model model.onnx # describe circuit structure
EVM On-Chain Verification
Generate a Solidity verifier contract, deploy to any EVM chain, verify proofs on-chain:
ezkl create-evm-verifier --vk-path vk.key --settings-path settings.json \
--sol-code-path verifier.sol --abi-path verifier.abi
ezkl deploy-evm --sol-code-path verifier.sol --rpc-url $RPC_URL --private-key $KEY
ezkl verify-evm --addr-verifier 0x... --proof-path proof.json --rpc-url $RPC_URL
See references/evm-integration.md for Solidity patterns, data attestation, and reusable verifiers.
Input Format
{
"input_data": [[1.0, 2.0, 3.0, 4.0]]
}
Model must be ONNX format. Export from PyTorch (torch.onnx.export), TensorFlow (tf2onnx), or scikit-learn (skl2onnx).
Performance Characteristics
| Model Type | Proving Time | Memory | |-----------|-------------|--------| | Linear Regression | ~0.12s | 19 MB | | SVM Classification | ~0.32s | 24 MB | | Tree Ensemble | ~0.31s | 24 MB | | Random Forest | ~6.2s | 383 MB |
GPU acceleration: ENABLE_ICICLE_GPU=true (NVIDIA via Icicle framework).
Limitations
- Quantization: Float to fixed-point causes minor output differences vs standard inference
- Non-linear ops are expensive: ReLU, sigmoid, GELU increase
logrowssignificantly - Large models: May require 30+ GB RAM for proving
- Not audited for production security (Trail of Bits review completed for v21.0.0 core compiler)
- ZKML does not prevent: adversarial inputs, membership inference, data poisoning
- License: Free for non-commercial; commercial use beyond certain version requires license
Additional Resources
Reference Files
references/python-api.md— Complete Python API with all function signaturesreferences/javascript-api.md— Full JS/TS SDK API, browser setup, field element conversionsreferences/evm-integration.md— Solidity verifier patterns, deployment, data attestationreferences/cli-reference.md— All CLI commands, GPU acceleration, Lilith cloud proving
Example Files
examples/bun-prove-verify.ts— Complete Bun example: witness generation, proving, verification