Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Launching a zkML Project for Private Predictions

A technical guide for developers to implement a zero-knowledge machine learning service that keeps user data private during on-chain inference.
Chainscore © 2026
introduction
GUIDE

Launching a zkML Project for Private Predictions

A practical guide to building and deploying a zero-knowledge machine learning model for generating private, verifiable predictions on-chain.

Zero-knowledge machine learning (zkML) enables smart contracts to use AI models without exposing the model's weights or the user's input data. This preserves privacy while maintaining cryptographic proof of correct execution. Projects like EZKL and Giza provide frameworks to compile standard machine learning models (e.g., from PyTorch or TensorFlow) into zk-SNARK circuits. The core workflow involves: - Model Training: Developing your model off-chain using traditional ML tools. - Circuit Compilation: Converting the trained model into an arithmetic circuit compatible with zk proof systems. - Proof Generation & Verification: Generating a zk-proof for a specific inference and verifying it on-chain.

To start a project, first define a use case requiring privacy and verifiability. Common applications include private credit scoring, anti-bot gaming mechanics, and confidential DAO voting sentiment analysis. For example, a lending protocol could use a zkML model to assess a user's creditworthiness based on private off-chain data, submitting only a proof of a 'pass' or 'fail' result to the chain. Choose a zkML framework based on your needs; EZKL is known for its Python integration and support for large models, while Giza offers a full-stack SDK for on-chain action execution.

The technical implementation begins after training your model. Using EZKL, you would export your PyTorch model to the ONNX format. Then, run EZKL's setup, prove, and verify commands. The setup phase creates the proving and verification keys. The prove command generates a proof for a given input, and verify checks it. A simplified workflow looks like this:

bash
ezkl setup --model-path model.onnx
ezkl prove --model-path model.onnx --input-path input.json

The generated proof and public outputs are what your smart contract will verify.

On-chain verification requires a smart contract that imports the verification key from the setup phase. Frameworks provide Solidity verifier contracts. For instance, after compiling with EZKL, you deploy a Verifier contract. Your main application contract then calls Verifier.verify(proof, public_inputs), which returns a boolean. Only if the proof is valid does the contract execute the subsequent logic, like minting an NFT for a proven high-score or issuing a loan. This keeps the model's internal calculations and the raw input data completely hidden from the blockchain.

Key considerations for production include cost and performance. Generating zk-proofs is computationally intensive; proving time and cost scale with model complexity. A small neural network might take minutes and cost dollars per proof, making it unsuitable for high-frequency transactions. Optimize by using simpler models, pruning, or leveraging specialized co-processors like Risc Zero or Succinct. Furthermore, ensure your model's output is deterministic, as any randomness will break proof generation. Always audit the circuit compilation process, as bugs here can lead to incorrect proofs being verified.

The landscape is evolving rapidly. Beyond EZKL and Giza, explore Modulus Labs for gaming-focused zkML or Worldcoin's zkML for identity. Start with a small proof-of-concept using a framework's tutorial, measure gas costs on a testnet, and iterate. The goal is to unlock new blockchain applications where privacy and trust in AI-driven decisions are paramount, moving beyond simple deterministic smart contract logic.

prerequisites
GETTING STARTED

Prerequisites and Setup

This guide outlines the core tools, frameworks, and accounts required to build a zero-knowledge machine learning (zkML) application for private on-chain predictions.

Before writing any code, you need to set up your development environment. The core stack for a zkML project involves three main components: a machine learning framework for model training, a zkSNARK proving system to generate cryptographic proofs of the model's computation, and a blockchain development environment to deploy and verify these proofs. For this guide, we will use PyTorch for the ML model, EZKL as the zkSNARK library, and Foundry for smart contract development. Ensure you have Python 3.9+, Node.js, and Rust installed on your system.

The first step is to install the specific libraries. Create a new Python virtual environment and install torch, torchvision, and ezkl. EZKL is a crucial tool that converts PyTorch models into circuits compatible with zkSNARKs. You can install it via pip: pip install ezkl. Simultaneously, set up your blockchain tooling. Install Foundry by running curl -L https://foundry.paradigm.xyz | bash followed by foundryup. This provides forge for contract compilation and testing, which we'll use to deploy a verifier contract.

You will also need access to a blockchain network for testing. While you can use a local Anvil node from Foundry, interacting with a live testnet is recommended for a realistic deployment. Obtain test ETH for Sepolia or Holesky from a faucet. Furthermore, set up an account with a Decentralized Oracle Network like Chainlink Functions or API3 if your model requires external data fetches for predictions. These services allow your smart contract to securely request and receive data, which is essential for dynamic, real-world inference scenarios.

With the software installed, the next phase is model preparation. Train or select a lightweight PyTorch model for your use case—common starters include a simple neural network for MNIST digit classification or a regression model. The model must be exported to the ONNX format, which is the intermediate representation EZKL uses. You can export a PyTorch model using torch.onnx.export(). Remember to also save a sample input tensor; this 'witness' data is used by EZKL to generate a proof that a specific input leads to a specific output, without revealing either.

Finally, configure your EZKL project. Run ezkl init to create a settings directory. You will need to generate proving and verification keys specific to your model. This is done using the ezkl setup command, which compiles your ONNX model into a circuit and creates these cryptographic keys. The settings.json file allows you to configure parameters like the scale of the field elements and the batch size for proofs. These settings impact proof generation time and size, so adjusting them is key to optimizing performance and cost for on-chain verification.

TECHNICAL SPECS

zkML Framework Comparison: EZKL vs. Giza

A side-by-side comparison of two leading frameworks for generating zero-knowledge proofs from machine learning models.

Feature / MetricEZKLGiza

Primary Language

Rust

Cairo

Proof System

Halo2

Cairo VM (StarkNet)

Model Format Support

ONNX, TensorFlow, PyTorch

ONNX, TensorFlow, PyTorch

Proving Time (ResNet-18)

~45 sec (CPU)

~25 sec (CPU)

Verification Time

< 1 sec

< 1 sec

Proof Size

~200 KB

~180 KB

Trusted Setup Required

Native On-Chain Verifier

EVM, Solana, Cosmos

StarkNet

Primary Use Case

General-purpose zkML

StarkNet-native AI agents

step-1-model-prep
FOUNDATION

Step 1: Prepare Your Machine Learning Model

The first step in launching a zkML project is converting your trained model into a format that can generate zero-knowledge proofs. This process, known as model compilation, is critical for performance and privacy.

Zero-knowledge machine learning (zkML) requires your model to be expressed within a zk-SNARK circuit. This means you cannot directly use models from frameworks like PyTorch or TensorFlow. Instead, you must convert your model into a format compatible with a zkVM or a circuit compiler. Popular tools for this include EZKL (for PyTorch models), Cairo (StarkNet), and Circom (for custom circuits). The choice of toolchain dictates the proving system (e.g., Groth16, PLONK) and impacts proving time and cost.

The compilation process involves several key transformations. First, your model's architecture and trained weights are serialized. The compiler then translates floating-point operations into finite field arithmetic, as zk-SNARKs operate over prime fields. This often requires quantization—converting 32-bit floats to integers—which can affect model accuracy. You must evaluate this trade-off. The output is a circuit file (like a .r1cs file in Circom) and a set of proving/verification keys.

Before compilation, optimize your model for the zkML environment. This includes: - Pruning to remove unnecessary neurons, reducing circuit size. - Using simpler activation functions (like ReLU) that are cheaper to prove than sigmoid or tanh. - Minimizing model size and depth, as each layer adds significant proving overhead. A model with 10,000 parameters will be vastly cheaper to prove than one with 1 million.

You must also prepare your inference pipeline. In zkML, the prover generates a proof that they ran the model on some private input data and obtained a specific output, without revealing the input. Your code must separate the model's public parameters (the circuit, verification key) from the private witness (the input data). Frameworks like EZKL handle this by providing APIs to generate proofs from private data and public model parameters.

Finally, test your compiled model thoroughly in a local development environment. Use the framework's tools to run a trusted setup (if required), generate a proof with sample data, and verify it. This confirms the circuit is correct before deploying to a blockchain. The proving time and memory usage here are your first indicators of on-chain feasibility. Only proceed to Step 2—deploying the verifier contract—once this local proof generation is reliable and performant.

step-2-circuit-compilation
IMPLEMENTATION

Step 2: Compile Model to a zk-SNARK Circuit

This step transforms your trained machine learning model into a format that can be proven and verified cryptographically, enabling private on-chain inference.

Compilation is the process of converting your model's inference logic into a zk-SNARK circuit. This circuit is a set of arithmetic constraints that precisely defines the model's forward pass—every matrix multiplication, activation function, and layer transformation. Tools like Circom or Halo2 are commonly used for this. You write a circuit template that takes the model weights (as private inputs) and a data sample (as a public input) and outputs the prediction, with all intermediate calculations constrained. The goal is to create a circuit that is both computationally efficient and cryptographically sound.

The primary challenge is representing floating-point operations, common in ML, within a finite field. You must quantize your model, converting weights and activations to integers. For example, a simple neural network layer y = ReLU(W * x + b) must be rewritten using integer arithmetic and a custom constraint for the ReLU function. This often involves scaling factors to preserve precision. The circuit complexity, measured in the number of constraints or R1CS gates, directly impacts proving time and cost. A ResNet-50 model, for instance, can generate millions of constraints.

A practical implementation involves exporting your trained model (e.g., from PyTorch as an ONNX file) and using a compiler like zkml or EZKL to transpile it into a circuit description. Here's a conceptual snippet for a linear layer in a Circom-like syntax:

code
template LinearLayer(n_in, n_out) {
  signal input weights[n_out][n_in];
  signal input bias[n_out];
  signal input x[n_in];
  signal output y[n_out];

  for (var i = 0; i < n_out; i++) {
    // Dot product constraint: y[i] = sum(weights[i][j] * x[j]) + bias[i]
    // ... constraint logic here ...
  }
}

This template defines the mathematical relationship without revealing the private weight values.

After defining the circuit, you must generate the proving key and verification key using a trusted setup (e.g., a Powers of Tau ceremony). The proving key allows the prover to generate a proof, while the compact verification key is used on-chain to check the proof's validity. It's critical to audit the circuit logic for correctness, as any error becomes a permanent vulnerability. Finally, you benchmark the compiled circuit for proving time and gas cost of verification to ensure practical usability for your application.

step-3-proof-generation
ZKML EXECUTION

Step 3: Generate Proofs from Private Inputs

This step transforms your private model and data into a cryptographic proof, the core artifact that enables verifiable computation without revealing the underlying information.

With your compiled circuit (the .r1cs file) and the proving key (.zkey) from the previous steps, you can now generate a zero-knowledge proof. This process uses your private inputs—the machine learning model weights and the prediction data—to execute the circuit logic and produce a proof of correct execution. The proof cryptographically attests that a valid computation occurred, but reveals nothing about the inputs themselves. For a simple linear model, your private inputs file (input.json) might look like this:

json
{
  "model_weights": [0.5, -1.2, 3.7],
  "input_data": [10, 25, 5]
}

You generate the proof using your chosen zk-SNARK backend. For example, with snarkjs and the Groth16 protocol, the command is:

bash
snarkjs groth16 prove circuit_final.zkey input.wtns proof.json public.json

This command does three things: it creates the proof.json file containing the actual cryptographic proof, generates a public.json file with any public outputs or signals, and consumes the witness file (input.wtns) you created during setup. The proof.json is a small, JSON-serialized file containing the proof points (A, B, C) that any verifier can check against the verification key.

The public output is crucial. In a zkML prediction, the result (e.g., prediction_score: 15.8) is typically made public, while the model and input data remain private. The proof verifies that this public output is the correct result of applying the private model to the private data. This separation enables use cases like proving a credit score without revealing income, or verifying an AI-generated image meets criteria without disclosing the model weights. The proof generation is the most computationally intensive step and runtime depends heavily on circuit complexity.

After generation, you should immediately verify the proof locally to ensure it's valid before broadcasting it on-chain or to a verifier service. Use snarkjs to check the proof against the verification key and public signals:

bash
snarkjs groth16 verify verification_key.json public.json proof.json

A successful verification returns OK, confirming the proof is mathematically sound. This local check prevents wasting gas on invalid on-chain verification. The final artifacts—the compact proof.json and public.json—are all that's needed for any party to cryptographically trust your model's private prediction.

step-4-contract-integration
ON-CHAIN INTEGRATION

Step 4: Deploy the Verification Smart Contract

This step moves the zkML model's proof verification logic onto the blockchain, enabling trustless, private inference.

The verification smart contract is the on-chain component that validates zero-knowledge proofs. It contains the verification key generated during the trusted setup and the public inputs required for the specific computation. When a user submits a proof, the contract runs a verify() function. This function cryptographically checks that the proof corresponds to a valid execution of the original model on some private input, without revealing that input. Successful verification triggers any associated on-chain logic, such as releasing funds or minting an NFT.

For deployment, you'll use a framework like Hardhat or Foundry. The contract is typically written in Solidity or a ZK-friendly language like Cairo or Noir. A common pattern is to use a verifier library, such as one generated by Circom's snarkjs or gnark, which provides a Solidity template. You must compile this contract and deploy it to your target network (e.g., Ethereum mainnet, a zkEVM like Polygon zkEVM, or a Layer 2 like Arbitrum). The contract address becomes the public endpoint for your application.

Key deployment considerations include gas cost and verification key size. Complex models produce large verification keys, which can make deployment expensive. Optimizations like using a verifier registry or proxy patterns can help. You must also manage the contract's state: who can submit proofs, how public inputs are formatted, and what happens after verification. Thorough testing with tools like Hardhat or Foundry is critical to ensure the on-chain logic correctly interprets the proof's public outputs.

step-5-optimization
PERFORMANCE TUNING

Step 5: Optimize Proof Size and Gas Costs

After your zkML model is verified, the next critical step is optimizing its on-chain performance. This step focuses on reducing proof size and gas costs to make your private predictions economically viable.

The computational cost of generating a zero-knowledge proof for a machine learning model is directly tied to the number of constraints in the circuit. For zkML, this translates to the model's complexity: the number of layers, neurons, and operations like matrix multiplications and activations. A model with millions of parameters will generate a proof that is large and expensive to verify on-chain. The primary goal is to minimize the constraint count without significantly compromising model accuracy. Techniques include using quantization to reduce the bit-width of model parameters from 32-bit floats to 8-bit integers, pruning to remove redundant neurons, and choosing more ZK-friendly activation functions like ReLU over sigmoid or tanh.

Proof size and verification gas are interrelated but distinct metrics. Proof size refers to the actual data (in bytes) that must be submitted in a transaction. Verification gas is the computational cost for the on-chain verifier smart contract to check the proof. While a smaller proof generally leads to lower gas, the verification algorithm's complexity also matters. For example, a Groth16 proof is smaller but requires a pairing operation on-chain, which is gas-intensive. PLONK or Halo2 proofs might be larger but have cheaper verification. You must benchmark your specific setup on a testnet. Use tools like snarkjs to measure proof size and a framework like Hardhat or Foundry to estimate gas costs for the verification function call.

Strategic batching can dramatically improve efficiency. Instead of submitting a proof for a single prediction, design your system to batch multiple user inferences into one proof. For instance, you could aggregate 100 private image classifications into a single batch proof. This amortizes the fixed overhead of proof generation and verification across many operations, reducing the average cost per prediction. Implementing this requires designing your circuit and application logic to accept batched inputs and outputs. Libraries like circomlib offer templates for operations like batch Merkle tree inclusion proofs, which can be adapted for batching model inferences.

Finally, consider the entire transaction lifecycle. The proof and public inputs (the model output) must be sent to the verifier contract. Use calldata optimization by ensuring all data is packed efficiently and using uint256 types where possible to minimize EVM storage overhead. For L2 solutions like zkRollups, understand their specific cost structures—data availability fees may be a larger factor than computation. Continuously profile your system using real-world inputs and adjust your model architecture and ZKP backend (e.g., switching from circom to gnark or tuning PLONK customization parameters) based on the results. The optimal configuration balances proof generation time, proof size, and verification cost for your specific use case.

use-cases
IMPLEMENTATION GUIDE

Practical zkML Use Cases

Explore concrete applications and tools for building zero-knowledge machine learning projects that enable private, verifiable on-chain inference.

06

Choosing Your zkML Stack

Select the right tools based on your project's needs. Key frameworks and their trade-offs:

  • EZKL: Python library to export PyTorch/TensorFlow models to Halo2 circuits. Best for Ethereum/Solidity.
  • Cairo (StarkNet): Write ML inference directly in Cairo; efficient proofs but locked into StarkNet ecosystem.
  • RISC Zero zkVM: Run existing Rust/Python ML code in a zero-knowledge virtual machine; easier dev experience but higher proving costs.
  • zkML (0xPARC): Research framework for converting models to zk-SNARKs; more experimental. Consider proof time, verification gas cost, and model complexity when choosing.
5-30 sec
Typical Proof Time
200k-2M gas
EVM Verification Cost
ZKML DEVELOPMENT

Frequently Asked Questions (FAQ)

Common technical questions and troubleshooting for developers building private machine learning applications with zero-knowledge proofs.

The workflow involves three main stages: model conversion, proof generation, and on-chain verification.

  1. Model Conversion: Convert your trained model (e.g., from PyTorch, TensorFlow) into a zk-friendly format. Frameworks like EZKL or Cairo require converting the model into a computational graph of arithmetic operations (often using ONNX as an intermediate step).
  2. Proof Generation (Client-side): The user provides a private input. A proving system (like Halo2, Plonky2, or RISC Zero) executes the model on this input and generates a zero-knowledge proof. This proof cryptographically attests that the model produced a specific output, without revealing the input.
  3. Verification (On-chain): A small, cheap verification smart contract (written in Solidity, Cairo, etc.) receives the proof and the public output. It verifies the proof's validity. Only if the proof is valid is the output accepted by the application.

The key is that the heavy computation (proof generation) happens off-chain, while the lightweight verification is on-chain.

conclusion
IMPLEMENTATION GUIDE

Conclusion and Next Steps

You have built a functional zkML pipeline for private predictions. This section outlines the critical next steps for moving from a prototype to a production-ready system.

Your development environment is now configured with zkML core components: a trained model in model.onnx, a proving circuit via ezkl, and a smart contract verifier. The next phase involves hardening this pipeline. Begin by benchmarking performance on your target chain. Use ezkl prove --settings settings.json with different KZG settings (e.g., 17, 18) to measure proving time, proof size, and gas costs for verification. For Ethereum mainnet, aim for proofs under 500k gas where possible. Document these metrics to inform your production architecture and cost model.

Security and trust are paramount. Audit your circuit to ensure it correctly represents your model's computation. Manually review the compiled_model.compiled file or use formal verification tools for the R1CS. For the on-chain component, consider having your verifier contract audited by a specialized firm. Furthermore, implement a robust secret management system for your prover keys. In a production setting, these should be stored in a secure, highly available service like HashiCorp Vault or AWS Secrets Manager, not in a local file.

To scale your application, design a reliable proving service. This could be a centralized cloud service you operate or a decentralized network of provers. The service must handle request queuing, load balancing, and proof generation with low latency. For user-facing applications, integrate a wallet connection (e.g., via Wagmi/viem) to allow users to submit private inputs and request proofs seamlessly. Your frontend should clearly communicate the proof generation status and provide the user with a transaction to submit the verified result on-chain.

Explore advanced zkML patterns to enhance your application. Recursive proof aggregation allows you to bundle multiple inferences into a single proof, drastically reducing on-chain verification costs for batch operations. You can also investigate model privacy, where the model weights themselves are a private input to the circuit, enabling users to verify a prediction came from a specific, undisclosed model. Libraries like circuits from Modulus Labs offer templates for these complex constructions.

Finally, engage with the ecosystem. Share your project on forums like the ZKML GitHub Discussions or the Modulus Discord. Contributing your verifier contracts or circuit templates back to the community helps advance the field. Monitor emerging Layer 2 solutions like zkSync Era or Polygon zkEVM, which offer native zk-friendly environments and may provide more efficient verification precompiles than the EVM, potentially reducing your costs by an order of magnitude.

How to Build a zkML Service for Private On-Chain Predictions | ChainScore Guides