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

Setting Up a Verifiable ML Model on a Blockchain

A technical guide for developers on encoding a machine learning model for blockchain deployment. Covers serialization, hash commitments, and creating a verifiable inference interface to ensure model integrity.
Chainscore © 2026
introduction
TUTORIAL

Setting Up a Verifiable ML Model on a Blockchain

A step-by-step guide to deploying a machine learning model with on-chain verifiable inference using the EZKL library and Ethereum.

On-chain verifiable machine learning allows anyone to verify the correctness of an ML model's inference without re-executing the entire computation. This is achieved using zero-knowledge proofs (ZKPs), specifically zk-SNARKs. A zk-SNARK proof cryptographically attests that a model produced a given output from a specific input, ensuring the computation was performed faithfully according to the published model weights. This creates trustless verification, enabling use cases like proving creditworthiness for a loan or verifying the output of an AI agent in a decentralized application.

The core technical workflow involves several key steps. First, you define your machine learning model using a framework like PyTorch. Next, you use a tool like EZKL to compile this model into a circuit representation understandable by zk-SNARK proving systems. This circuit, along with the model's fixed parameters (weights), becomes the verifiable program. You then generate a trusted setup to create the proving and verification keys required for the specific circuit. Finally, you can generate proofs for individual inferences and verify them on-chain.

To implement this, start by installing EZKL: pip install ezkl. Export your trained PyTorch model to the ONNX format, which serves as a standard intermediate representation. You'll also need to export sample input and output data to define the shape of the computation. The following command compiles the model into a circuit: ezkl compile-circuit -M model.onnx --compiled-circuit model.ezkl. This creates the .ezkl file containing the arithmetic circuit.

With the circuit compiled, you must run a trusted setup to generate the cryptographic keys. Execute ezkl setup -M model.ezkl. This produces a model.pk (proving key) and a model.vk (verification key). The verification key is small enough to be stored on-chain. For actual inference, you generate a proof by running ezkl prove -M model.ezkl --pk-path model.pk. This command takes a specific input, runs the model, and produces a proof.json file containing the zk-SNARK proof attesting to the correct execution.

The final step is on-chain verification. You deploy a verifier smart contract to a blockchain like Ethereum. This contract is generated from your verification key (model.vk) using EZKL's ezkl create-evm-verifier command. The contract exposes a verify function. To verify an inference, you submit the proof (proof.json) to this function. The contract performs a cryptographic check; if it returns true, the inference is verified as correct without revealing the private input data. This enables decentralized applications (dApps) to trustlessly consume ML outputs.

Practical considerations include gas costs for on-chain verification and circuit size limits. Proving time and cost scale with model complexity. Start with small models (e.g., a simple neural network for MNIST digit classification) before scaling up. The primary use cases are scenarios requiring auditable and tamper-proof AI, such as verifiable randomness from ML models, proof of fair execution in prediction markets, or privacy-preserving identity verification. The field is rapidly evolving with projects like Giza, Modulus, and Risc Zero offering alternative stacks for verifiable computation.

prerequisites
VERIFIABLE ML ON-CHAIN

Prerequisites and Setup

This guide outlines the technical requirements and initial steps for deploying a machine learning model in a verifiable manner on a blockchain.

Verifiable ML on a blockchain requires a specific technical stack. You will need a foundational understanding of smart contract development, typically using Solidity for Ethereum Virtual Machine (EVM) chains or Rust for Solana. Familiarity with machine learning frameworks like PyTorch or TensorFlow is essential for model creation. Finally, you must choose a verification protocol such as zk-SNARKs (via Circom or Halo2) or optimistic fraud proofs to generate cryptographic proofs of correct model execution. These components form the core of a system where inference can be proven trustlessly.

The first practical step is environment setup. Install Node.js (v18+), Python (3.9+), and a package manager like yarn or npm. For EVM development, set up Hardhat or Foundry. You will also need cryptographic tooling; for zk-SNARKs, this includes Circom and snarkjs. A critical preparatory task is model optimization. Deploying a full neural network on-chain is prohibitively expensive. You must convert your trained model into an inference-optimized format—such as ONNX—and then further compile it into a circuit-compatible representation (e.g., R1CS) for zero-knowledge proofs or a deterministic bytecode for fraud-proof systems.

Next, establish your development workflow. Create a monorepo with separate directories for: the ML model training scripts (/model), the circuit or verifier logic (/circuits), and the smart contracts that will verify and store proofs (/contracts). Use a .env file to manage configuration like RPC endpoints and private keys for testnets. Begin by writing a simple test: generate a proof for a single model inference off-chain, then use a local blockchain (e.g., Hardhat Network) to call a verifier contract and validate the proof. This end-to-end test confirms your toolchain is correctly configured before proceeding to more complex models.

step-1-serialization
DATA PREPARATION

Step 1: Model Serialization and Compression

Before a machine learning model can be verified on-chain, its architecture and parameters must be converted into a deterministic, compact format suitable for blockchain storage and computation.

The first technical hurdle in on-chain ML is representing a model as a deterministic data structure. Frameworks like PyTorch or TensorFlow save models in formats (.pt, .h5) that are not inherently portable or verifiable. Serialization converts the model's computational graph and all learned parameters into a standardized format like ONNX (Open Neural Network Exchange). This creates a language-agnostic representation that can be executed by various runtimes, forming the foundation for verifiable inference. For example, a ResNet-50 model trained in PyTorch can be exported to an onnx file, which precisely defines every layer, weight, and operation.

Directly storing a raw serialized model on-chain is prohibitively expensive. A typical ONNX file for a modest model can be several megabytes, and Ethereum gas costs scale linearly with data size. Model compression techniques are therefore essential. Two primary methods are used: quantization and pruning. Quantization reduces the numerical precision of model parameters from 32-bit floats to 8-bit integers (INT8), shrinking the model size by ~75% with minimal accuracy loss. Pruning removes redundant neurons or weights that contribute little to the model's output, further reducing the parameter count. Libraries like TensorRT or ONNX Runtime provide tools to apply these optimizations.

The compressed, serialized model must then be encoded into a format the blockchain can process. This typically involves generating a cryptographic hash (like SHA-256 or Keccak-256) of the model's bytecode. This hash, or model commitment, is a fixed-size fingerprint (32 bytes) that is stored on-chain. The actual model data is stored off-chain in decentralized storage like IPFS or Arweave, with its content identifier (CID) linked to the on-chain commitment. Any verifier can later fetch the model data, recompute its hash, and compare it to the on-chain commitment to ensure the correct, unaltered model is being used for computation.

step-2-hash-commitment
MODEL VERIFICATION

Step 2: Creating a Cryptographic Commitment

Learn how to generate a unique, tamper-proof fingerprint of your machine learning model to anchor it on-chain.

A cryptographic commitment is a foundational concept for on-chain verification. It involves generating a short, deterministic fingerprint—a hash—from your model's parameters. This hash acts as a binding promise; you commit to a specific model state without revealing the full data. The most common method is using a cryptographic hash function like SHA-256 or Keccak-256. The key property is that any change to the input model, even a single weight, will produce a drastically different output hash, making tampering detectable.

To create a commitment, you must first serialize your model's state into a consistent byte format. For a PyTorch model, you can use torch.save(model.state_dict()) and then hash the resulting file. For TensorFlow, you can serialize the model's weights using model.get_weights() and a library like pickle. The critical step is ensuring the serialization is deterministic—the same model must always produce the identical byte sequence. Any non-determinism in the process will break the verification link.

Here is a practical Python example using SHA-256 for a PyTorch model:

python
import hashlib
import torch
import torch.nn as nn

# Define a simple model
model = nn.Linear(10, 2)
# Serialize the state dictionary to bytes
model_bytes = torch.save(model.state_dict(), f=None)
# Create the cryptographic hash (commitment)
commitment_hash = hashlib.sha256(model_bytes).hexdigest()
print(f'Model Commitment: {commitment_hash}')

This commitment_hash is the value you will store on-chain, for instance, by emitting it in a smart contract event or writing it to contract storage.

For larger models, the serialized data can be substantial. In such cases, consider committing to a Merkle root instead. You can split the model parameters into chunks, hash each chunk, and then build a Merkle tree. The root of this tree becomes your compact commitment. This approach, used by protocols like zkSync and Arbitrum for data availability, allows you to prove the inclusion of specific parameters later without needing the entire dataset on-chain.

Once generated, this commitment must be published to your chosen blockchain. This is typically done by calling a function in a verification smart contract, such as commitModel(bytes32 commitmentHash). Storing the hash on a public ledger like Ethereum or Polygon creates an immutable, timestamped record. This record is the anchor for all future proofs, enabling anyone to verify that a submitted model's hash matches the original commitment.

step-3-inference-interface
ARCHITECTURE

Step 3: Designing the Verifiable Inference Interface

Define the on-chain smart contract that will request, verify, and accept proofs of your model's inferences.

The verifiable inference interface is the smart contract that acts as the blockchain's gateway to your model. Its primary function is to define a request-response pattern where users submit input data, and the contract accepts a zero-knowledge proof (ZKP) that cryptographically verifies the inference was executed correctly by your pre-defined model. This contract does not run the model; it only verifies the proof. A typical interface includes functions like requestInference(bytes calldata input) to initiate a request and submitProof(uint256 requestId, bytes calldata proof) to finalize it.

Your contract must store the verification key for your specific model. This key is generated during the trusted setup or circuit compilation phase (Step 2) and is unique to your model's architecture. The contract uses this key to validate any submitted proof. In Solidity, this often involves calling a verifier contract library. For example, using the snarkjs and circom toolchain, you would deploy a Groth16Verifier contract and have your main interface store its address, delegating proof verification to it.

A critical design decision is managing state and fees. You must decide if the interface stores inference results on-chain or simply emits an event. On-chain storage is gas-intensive but provides permanent availability, while events are cheaper and sufficient for many applications. Furthermore, you may need a fee mechanism to compensate the prover (the off-chain service that generates the proof) for their computational work. This can be implemented via a required payment in the requestInference function.

To ensure security and correctness, the interface must validate that the submitted proof corresponds to the original request. This involves checking that the public signals embedded within the ZKP hash to the expected request ID and input data. Without this check, a prover could submit a valid proof for a different input. The contract should also include access controls, pausing mechanisms, and a way to update the verification key if the model is upgraded, though this requires a new trusted setup.

Here is a simplified Solidity snippet outlining the core structure:

solidity
interface IVerifiableInference {
    function requestInference(bytes calldata input) external payable returns (uint256 requestId);
    function submitProof(uint256 requestId, bytes calldata proof, bytes32[] calldata publicSignals) external;
    event InferenceRequested(uint256 indexed requestId, address indexed requester, bytes input);
    event InferenceCompleted(uint256 indexed requestId, bytes output);
}

The publicSignals array contains the output of the computation and any public inputs, which the verifier contract uses to check the proof.

Finally, consider integration with oracles or relayers. In a production system, an off-chain agent (a prover network) typically monitors the InferenceRequested event, runs the model, generates the ZKP, and calls submitProof. Your interface design should make this interaction seamless and gas-efficient. Successful implementation means any user or smart contract can trustlessly request a verifiable ML inference, creating a foundational primitive for on-chain AI applications.

step-4-off-chain-prover
IMPLEMENTATION

Step 4: Building the Off-Chain Prover Service

This step details the creation of the off-chain service that generates zero-knowledge proofs for your machine learning model's inference results, enabling on-chain verification.

The off-chain prover service is the core computational engine of a verifiable ML system. Its primary function is to execute the trained model on new input data and generate a zero-knowledge proof (ZKP) that cryptographically attests to the correctness of the computation. This proof is then submitted to the blockchain's verifier contract. You can build this service using frameworks like Circom for circuit design and SnarkJS for proof generation, or leverage higher-level libraries such as EZKL which is specifically designed for ML models.

Start by exporting your trained model into a format the proving system can understand. For a PyTorch model, you would typically export it to ONNX (Open Neural Network Exchange) format. This ONNX file, along with a structured input JSON file containing your sample data, serves as the input for the proving circuit. The circuit itself, written in a domain-specific language like Circom's R1CS, defines the computational graph of your model's forward pass, including all operations like matrix multiplications and activation functions, transforming them into arithmetic constraints.

The proving process is computationally intensive. For production, this service should run on a dedicated server or within a cloud function (e.g., AWS Lambda, Google Cloud Run) that can scale. A typical workflow involves: 1) Receiving an inference request via an API, 2) Loading the model and input data, 3) Executing the model to get the output, 4) Generating the ZKP using the pre-compiled proving key, and 5) Returning both the plaintext result and the proof to the client or directly to the blockchain. The proving key is a large file generated during a one-time trusted setup and must be securely stored and served by this service.

Optimization is critical. Naively proving every floating-point operation is prohibitively expensive. Common techniques include quantizing the model to use fixed-point arithmetic (e.g., converting 32-bit floats to 16-bit integers), which drastically reduces circuit size and proof generation time. Tools like EZKL handle this quantization automatically. You must also consider batching proofs for multiple inferences or using recursive proofs to aggregate verification, which can reduce on-chain gas costs significantly.

Finally, the service must be robust and secure. Implement proper error handling for proof generation failures, logging for audit trails, and rate limiting to prevent abuse. The integrity of the proving key is paramount; if compromised, an attacker could generate valid proofs for incorrect results. Consider using hardware security modules (HSMs) or trusted execution environments (TEEs) for key storage in high-value applications. The completed service creates a trustless bridge between off-chain complex computation and on-chain, verifiable truth.

TECHNICAL TRADEOFFS

Model Commitment Strategy Comparison

Methods for committing a machine learning model's parameters to a blockchain for verifiable inference, balancing cost, privacy, and verification complexity.

Feature / MetricOn-Chain StorageMerkle Tree RootZK-SNARK Commitment

Data Stored On-Chain

Full model parameters

32-byte root hash

~1-2 KB proof data

Gas Cost (Ethereum, 1M params)

$800-1200

$40-60

$120-200 (proving + verification)

Parameter Privacy

None (fully public)

Full (hash only)

Full (zero-knowledge)

Verification On-Chain

Direct read

Merkle proof (~10-50 KB)

Proof verification (fixed gas)

Update Flexibility

High (direct overwrite)

Medium (new root per update)

Low (new proof per update)

Inference Verification

Direct computation

Off-chain compute, on-chain proof

ZK proof of correct inference

Suitable For

Small, public models

Large, private models

Private models requiring verifiable execution

Implementation Complexity

Low

Medium

High (requires circuit setup)

step-5-integration-testing
VERIFIABLE ML PIPELINE

Step 5: End-to-End Integration and Testing

This final step connects all components into a functional system and validates the integrity of the verifiable ML workflow on-chain.

With the model deployed as a zkML circuit and its metadata stored on-chain, the final stage is to create a client application that interacts with the entire pipeline. This involves writing a script that: (1) loads a new input, (2) generates a zk-SNARK proof of the model's inference, (3) submits the proof and public outputs to the verifier smart contract, and (4) retrieves and trusts the verified result. Use frameworks like Hardhat or Foundry to script this interaction in a test environment. The core function will call the verifier contract's verifyProof method, passing the proof (a, b, c arrays) and public signals (the model hash and output).

A comprehensive test suite is critical. You should test multiple scenarios: valid inferences with correct proofs, invalid proofs that should be rejected, and tampered inputs or model hashes. For Ethereum-based chains, use the chai assertion library with Hardhat. A key test verifies that the on-chain model hash (stored in Step 4) matches the hash of the circuit used to generate the proof. This ensures the proof corresponds to the officially registered model. Also, test gas consumption for the verifyProof call to estimate operational costs.

For a complete Continuous Integration (CI) pipeline, integrate these tests with GitHub Actions or GitLab CI. The workflow should: - Install dependencies (Circom, snarkjs, Foundry). - Compile the circuit and generate the verifier contract. - Run the full test suite against a local blockchain node (e.g., Hardhat Network). This automation ensures any change to the model or circuit logic is immediately validated. Consider adding a final test that uses a public testnet (like Sepolia or Holesky) to confirm real-world transaction execution and gas costs before mainnet deployment.

Finally, document the end-to-end process and provide clear examples. Include a README with: the command sequence to run a full demo, the structure of the proof generation script, and the ABI of the verifier contract. This enables other developers to audit and integrate your verifiable model. The ultimate goal is a reproducible pipeline where any user can independently verify that a given AI output was produced by a specific, unaltered model, fully leveraging the blockchain's trust guarantees.

tools-and-frameworks
VERIFIABLE ML ON-CHAIN

Tools and Frameworks

Essential tools for developing, verifying, and deploying machine learning models on blockchain infrastructure.

06

Development Workflow & Testing

A practical workflow for building a verifiable ML application.

  1. Model Development: Train and export your model to ONNX.
  2. Circuit Setup: Use EZKL or Giza SDK to set up the proving circuit and generate verification keys.
  3. Local Testing: Run proofs locally on sample data to verify correctness and measure performance.
  4. Smart Contract Integration: Deploy the verifier contract and create a frontend to submit proofs.
  • Tool: Use Hardhat or Foundry for contract development and testing.
VERIFIABLE ML ON-CHAIN

Frequently Asked Questions

Common technical questions and troubleshooting steps for developers implementing verifiable machine learning models on blockchain infrastructure.

A verifiable ML model is a machine learning system where its execution (inference) can be cryptographically proven, typically using zero-knowledge proofs (ZKPs) or optimistic fraud proofs. Putting the verification mechanism on-chain allows for trustless verification of model outputs. This is critical for applications like:

  • DeFi: Using ML for credit scoring or risk assessment without a trusted oracle.
  • Gaming/NFTs: Provably fair AI-driven game mechanics or generative art.
  • DAOs: Transparent, auditable voting on proposals analyzed by AI.

The core value is verifiability, not storing the entire model on-chain. The model weights and verification logic (e.g., a zk-SNARK circuit) are often stored off-chain or in decentralized storage (like IPFS), with only the compact proof and public inputs/outputs submitted to the blockchain for verification and consensus.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have successfully deployed a verifiable ML model on-chain, enabling transparent and trustless inference. This guide covered the core workflow from model preparation to on-chain verification.

This tutorial demonstrated a foundational architecture for verifiable machine learning on a blockchain. By using a zkML framework like EZKL or Giza, you can convert a standard PyTorch or TensorFlow model into a zero-knowledge proof circuit. The resulting proof, verified by a smart contract, cryptographically guarantees that a specific inference was executed correctly against the declared model and input data. This creates a powerful primitive for applications requiring auditability, such as decentralized AI oracles, verifiable content moderation, and transparent credit scoring.

To extend this setup, consider these next steps. First, optimize your model for the proving system by reducing its size and complexity, as proving time and cost scale with the number of operations. Tools like model pruning and quantization are essential. Second, explore off-chain proving with on-chain verification to manage gas costs, using a system like Cartesi or a custom optimistic rollup. Finally, integrate your verifiable model into a decentralized application (dApp). For instance, build a prediction market where outcomes are settled by verified model inferences or a DAO that uses an on-chain model for proposal filtering.

The ecosystem for verifiable computation is rapidly evolving. Stay updated on new proving systems like RISC Zero and SP1, which offer different trade-offs in prover speed and proof size. Monitor Layer 2 solutions like zkSync and StarkNet for native zkML support, which can drastically reduce verification costs. For further learning, review the documentation for EZKL, Giza, and the Circom language. The ultimate goal is to move beyond isolated proofs and towards composable, verifiable AI agents that can interact autonomously and trustlessly within the broader DeFi and Web3 ecosystem.