Skip to main content

Command Palette

Search for a command to run...

Can You Prove an AI Ran Correctly? — ZK Proofs Meet Machine Learning

Part 3 of 3 in the Zero-Knowledge Proofs series. The frontier where cryptography meets AI — and why it's harder than anyone admits.

Updated
17 min read
N
Devoloping in web3 and AI

Can You Prove an AI Ran Correctly? — ZK Proofs Meet Machine Learning

Part 3 of 3 in the Zero-Knowledge Proofs series. The frontier where cryptography meets AI — and why it's harder than anyone admits.

We've come a long way.

In Part 1, we learned what Zero-Knowledge Proofs are — the Ali Baba cave, the three properties, the simulator argument, Fiat-Shamir.

In Part 2, we learned how to prove arbitrary computations — circuits, R1CS, QAP, SNARKs vs STARKs, ZK rollups.

Now we're at the edge of what's actually solved.

Here's the question Part 3 answers:

Can you prove that an AI model ran correctly — without revealing the model?

Prove that a specific neural network, given a specific input, produced a specific output. Without revealing the model's weights. Without revealing the input if it's private. With a cryptographic proof that anyone can verify.

This is called zkML — Zero-Knowledge Machine Learning. And it's simultaneously one of the most important ideas in AI and one of the hardest engineering problems in cryptography.

Let me show you exactly why — and exactly how far we've gotten.


Why This Problem Matters

Before the technical deep dive, let's establish why anyone should care.

The AI Trust Crisis

Right now, when an AI system makes a decision that affects your life — a loan approval, a medical diagnosis, a content moderation call — you have exactly zero ability to verify it.

The company says: "Our AI decided X."

You have no way to verify:

  • That their AI actually made that decision (vs a human overriding it)

  • That the model they used is the model they claim to use

  • That the model wasn't manipulated between training and deployment

  • That the decision was actually based on the inputs they say it was

This is a trust problem. And trust problems are exactly what ZK proofs were designed to solve.

The Specific Use Cases

Use Case 1 — AI API Verification
  Provider claims: "We ran GPT-X on your input"
  ZK proof proves: This specific model produced this output
  Without revealing: The model weights (proprietary)

Use Case 2 — Fair AI Compliance
  Bank claims: "Our loan model didn't use race as a feature"
  ZK proof proves: The model's decision path never touched protected attributes
  Without revealing: The model itself (trade secret)

Use Case 3 — On-Chain AI Agents
  Agent claims: "I computed this action off-chain"
  ZK proof proves: The computation was correct
  Without revealing: Private input data

Use Case 4 — Private Medical AI
  Hospital claims: "AI diagnosed this condition"
  ZK proof proves: The diagnosis came from a certified model
  Without revealing: Patient data (HIPAA) or model weights

In every case, the pattern is the same: prove correctness without revealing secrets.

That's exactly what ZK proofs do. The problem is that neural networks are spectacularly hostile to ZK proof systems.


Why Neural Networks Hate ZK Circuits

Remember from Part 2 that ZK proofs work by converting computations into arithmetic circuits — graphs of addition and multiplication gates over a finite field.

Neural networks, on the surface, seem like they'd map nicely to circuits. They're just matrix multiplications and activation functions, right?

Wrong. Here's where it falls apart.

Problem 1: The Floating Point Catastrophe

ZK proof systems work over finite fields — integers modulo a large prime number p. Every value in the computation must be an integer in the range [0, p-1].

Neural networks use floating point arithmetic — IEEE 754 floats with 32-bit or 16-bit representations, sign bits, exponents, mantissas.

Neural network weight: 0.3847291...  (float32)
ZK circuit expects:    an integer in [0, p-1]

These are fundamentally different number systems.

To make a neural network ZK-provable, you must quantize it — convert all weights and activations to fixed-point integers.

Float weight:  0.3847291
Scale by 2^16: 25,217 (fixed-point integer)

Now it's ZK-compatible. But...

Every quantization introduces error. The quantized model produces slightly different outputs than the original. And that difference matters — because your ZK proof proves the quantized model ran correctly, not necessarily that it matches the original float model's behavior.

For small models on classification tasks, this error is acceptable. For large language models where token probabilities matter enormously — it's a serious problem.

Problem 2: The Activation Function Nightmare

The core operation of a neural network layer is:

output = activation(W · x + b)

Where W · x + b is a matrix multiplication — perfectly fine in ZK circuits, just a lot of multiply-add constraints.

The activation function is the problem.

ReLU: f(x) = max(0, x)

To prove ReLU in a ZK circuit, you need to prove a comparison: x < 0 or x ≥ 0. Comparisons require bit decomposition — proving the bit representation of a number, then checking the sign bit.

Proving x ≥ 0 in a ZK circuit:
  1. Decompose x into n bits: x = b₀ + 2b₁ + 4b₂ + ... + 2^(n-1)b_{n-1}
  2. Prove each bᵢ ∈ {0,1}: bᵢ * (1 - bᵢ) = 0  (one constraint per bit)
  3. Prove the decomposition is correct: sum = x  (one constraint)
  4. Check sign bit

For a 32-bit number: ~34 constraints per ReLU
A small ResNet has ~500,000 ReLU activations
Total: ~17,000,000 constraints just for activations

GELU: f(x) = x · Φ(x) where Φ is the Gaussian CDF

Even worse. GELU involves a non-algebraic function (the error function). There's no exact circuit representation — you need polynomial approximations, which add approximation error on top of quantization error.

Softmax: f(xᵢ) = e^xᵢ / Σe^xⱼ

Exponentials. Division. Both catastrophically expensive in finite field arithmetic.

The fundamental problem: neural network operations were designed for hardware that's excellent at floating point arithmetic. ZK circuits are algebraic structures designed for integer arithmetic in finite fields. These two worlds were not designed to work together.

Problem 3: The Scale Problem

Let's talk numbers.

GPT-2 (small, 117M parameters):
  Layers: 12
  Attention heads per layer: 12
  Each forward pass: ~10^9 multiply-accumulate operations

ZK prover speed (modern hardware): ~10^6 constraints/second

Estimated proving time for one GPT-2 forward pass:
  ~10^9 / 10^6 = ~1,000 seconds = ~17 minutes

For GPT-3 (175B parameters):
  ~25,000× larger than GPT-2
  Estimated proving time: months

This isn't a software optimization problem. It's a fundamental scaling challenge.

Current ZK systems can practically prove:

✅ Models with < 10M parameters
✅ Specific layers in isolation
✅ Quantized INT8/INT4 models with simplified activations
✅ Tree-based models (decision trees, random forests)
✅ Linear and logistic regression
⚠️  Small CNNs (ResNet-18: ~30 seconds on M2 Mac)
❌  Transformer models at GPT-2 scale
❌  Any frontier LLM

Problem 4: The Memory Wall

STARK provers need to hold the entire execution trace in memory during proof generation.

Execution trace size ≈ (number of steps) × (number of registers)

For a small transformer layer:
  Steps: ~10^6
  Registers: ~10^3
  Trace size: ~10^9 entries × 32 bytes = ~32 GB RAM

For a full GPT-2 forward pass:
  Trace size: Multiple terabytes

You'd need a machine with terabytes of RAM just to generate the proof. That's not a data center configuration — it's a fantasy configuration.


What's Actually Working Today

Okay, enough about what doesn't work. Here's the honest picture of what does.

EZKL — The Most Production-Ready zkML Library

EZKL (Easy Zero-Knowledge for Machine Learning) is the most mature zkML framework available today. It converts ONNX models (the standard ML model format) directly into Halo2 circuits.

# The zkML workflow with EZKL

import ezkl
import torch
import json

# Step 1: Export your model to ONNX
model = YourSmallModel()
dummy_input = torch.randn(1, 28, 28)  # e.g., MNIST image
torch.onnx.export(model, dummy_input, "model.onnx")

# Step 2: Define circuit settings
# This is where you configure quantization precision
settings = ezkl.PyRunArgs()
settings.input_visibility = "public"   # input is public
settings.output_visibility = "public"  # output is public  
settings.param_visibility = "private"  # weights are private ← the key

# Step 3: Calibrate (analyze the model's numerical range)
# EZKL figures out the optimal quantization scale
await ezkl.calibrate_settings("model.onnx", "input.json", "settings.json")

# Step 4: Compile the model into a ZK circuit
await ezkl.compile_circuit("model.onnx", "model.compiled", "settings.json")

# Step 5: Generate proving and verification keys
# (This is the setup phase — done once per model)
await ezkl.setup("model.compiled", "vk.key", "pk.key")

# Step 6: Generate a witness (the private computation trace)
await ezkl.gen_witness("input.json", "model.compiled", "witness.json")

# Step 7: Generate the proof
await ezkl.prove("witness.json", "model.compiled", "pk.key", "proof.json")

# Step 8: Verify the proof
result = await ezkl.verify("proof.json", "settings.json", "vk.key")
print(f"Proof valid: {result}")  # True

What EZKL handles for you:

  • Automatic quantization of float weights to fixed-point integers

  • Conversion of activation functions to polynomial approximations

  • Circuit compilation with Halo2

  • Solidity verifier export for on-chain verification

Real performance numbers (as of 2026):

Model               | Params  | Prove Time | Proof Size
--------------------|---------|------------|------------
Logistic regression | ~1K     | <1 sec     | ~50 KB
Small MLP (MNIST)   | ~100K   | ~2 sec     | ~200 KB
ResNet-18           | 11M     | ~30 sec    | ~800 KB
MobileNet-V2        | 3.4M    | ~15 sec    | ~500 KB
BERT-tiny           | 4.4M    | ~3 min     | ~2 MB
GPT-2 (full)        | 117M    | Not feasible | —

The sweet spot today: models under ~10M parameters on specialized hardware.

The Working Example: A ZK MNIST Classifier

Let me show you what a complete zkML proof actually looks like end-to-end.

The model — a small CNN that classifies handwritten digits:

import torch
import torch.nn as nn

class MNISTClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, 3, padding=1)   # 16 filters
        self.conv2 = nn.Conv2d(16, 32, 3, padding=1)  # 32 filters
        self.fc1 = nn.Linear(32 * 7 * 7, 128)
        self.fc2 = nn.Linear(128, 10)
        self.relu = nn.ReLU()
        self.pool = nn.MaxPool2d(2)
    
    def forward(self, x):
        x = self.pool(self.relu(self.conv1(x)))  # 28x28 → 14x14
        x = self.pool(self.relu(self.conv2(x)))  # 14x14 → 7x7
        x = x.view(-1, 32 * 7 * 7)
        x = self.relu(self.fc1(x))
        return self.fc2(x)  # logits for 10 classes

# Parameters: ~408K — within EZKL's practical range

What the ZK proof proves:

Public inputs:
  → Input image (28×28 pixels, normalized)
  → Output logits (10 class scores)
  → Model commitment (hash of the weights)

Private inputs (never revealed):
  → The model weights (~408K float32 values)
  → All intermediate activations

The proof certifies:
  "A model with this specific commitment, given this image,
   produced these exact logits — computed correctly according
   to the circuit constraints."

The Solidity verifier (auto-generated by EZKL):

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MNISTVerifier {
    // Verification key embedded at compile time
    // (contains the model commitment implicitly)
    
    function verifyProof(
        bytes calldata proof,
        uint256[] calldata publicInputs
    ) public view returns (bool) {
        // publicInputs contains:
        // [0..783]:   flattened image pixels (public)
        // [784..793]: output logits (public)
        
        // Runs Halo2 verification logic
        // Returns true iff the proof is valid
        return _verify(proof, publicInputs);
    }
}

A smart contract can now trustlessly verify that a specific neural network produced a specific classification — without ever seeing the model weights.


The Circom Approach: Building ZK Circuits Manually

For simpler ML operations, you can write ZK circuits directly in Circom. This gives you more control but requires deep understanding of the constraints.

Here's a ZK proof for a simple dot product — the core operation in a linear layer:

pragma circom 2.0.0;

// Prove: public_output = sum(weights[i] * input[i])
// Without revealing: weights (private)
// Public: input, output

template DotProduct(n) {
    signal input weights[n];   // private: model weights
    signal input inputs[n];    // public: user input
    signal output out;         // public: layer output
    
    signal products[n];
    signal running_sum[n+1];
    
    running_sum[0] <== 0;
    
    for (var i = 0; i < n; i++) {
        // Each multiplication becomes one R1CS constraint
        products[i] <== weights[i] * inputs[i];
        running_sum[i+1] <== running_sum[i] + products[i];
    }
    
    out <== running_sum[n];
}

// A 3-neuron layer
component main {public [inputs]} = DotProduct(3);

For input [1, 2, 3] with private weights [0.5, 0.3, 0.2] (quantized to [5, 3, 2] with scale 10):

products[0] = 5 * 1 = 5
products[1] = 3 * 2 = 6
products[2] = 2 * 3 = 6
out = 5 + 6 + 6 = 17  (divide by scale: 1.7)

The proof verifies this output was computed with some weights satisfying the circuit — without revealing [5, 3, 2].

Now add a ReLU:

pragma circom 2.0.0;
include "comparators.circom";
include "bitify.circom";

// ZK ReLU: prove output = max(0, input)
template ReLU(bits) {
    signal input in;
    signal output out;
    signal isNegative;
    
    // Decompose into bits to check sign
    component n2b = Num2Bits(bits);
    n2b.in <== in + (1 << (bits-1));  // offset to handle negatives
    
    // The most significant bit tells us the sign
    isNegative <== n2b.out[bits-1];
    
    // out = in * (1 - isNegative)
    // If negative: out = in * 0 = 0
    // If positive: out = in * 1 = in
    out <== in * (1 - isNegative);
}

template LinearLayerWithReLU(n, bits) {
    signal input weights[n];
    signal input inputs[n];
    signal output out;
    
    // First compute dot product
    component dot = DotProduct(n);
    for (var i = 0; i < n; i++) {
        dot.weights[i] <== weights[i];
        dot.inputs[i] <== inputs[i];
    }
    
    // Then apply ReLU
    component relu = ReLU(bits);
    relu.in <== dot.out;
    out <== relu.out;
}

component main {public [inputs]} = LinearLayerWithReLU(3, 32);

This is what EZKL automates for an entire neural network. The circuit can have millions of these constraints. The proof certifies all of them hold simultaneously.


The Research Frontier: What's Being Worked On

The gap between "works for small models" and "works for GPT-4" is enormous. Here's what researchers are actively attacking:

Recursive Proof Aggregation

Instead of proving an entire model in one massive proof, prove each layer independently and then recursively combine the proofs:

Layer 1 proof: π₁ (proves layer 1 ran correctly)
Layer 2 proof: π₂ (proves layer 2 ran correctly, given layer 1's output)
...
Layer N proof: πₙ

Aggregation proof: π_final
  Proves: "π₁, π₂, ..., πₙ are all valid"
  Size: same as one proof
  Verify time: same as one proof

This allows parallelizing the proving work across many machines. Each machine proves one layer. A final aggregation step combines them.

Halo2 and Plonky2 are designed for efficient recursive proof aggregation. This is probably the most promising path to practical zkML for larger models.

Hardware Acceleration

Current bottleneck: the mathematical operations in ZK provers (multi-scalar multiplication, number theoretic transforms) are computationally intensive.

CPU prover:    baseline
GPU prover:    10-50× faster  (parallelizing field arithmetic)
FPGA prover:   50-100× faster (custom circuits for ZK operations)
ASIC prover:   100-1000× faster (purpose-built silicon)

Companies building ZK hardware accelerators (Ingonyama, Cysic, and others) are making proving times drop fast. What takes 30 minutes today on a CPU might take 30 seconds on a ZK ASIC in three years.

ZK-Friendly Neural Architectures

Instead of forcing existing neural network architectures through ZK circuits — design architectures specifically for ZK provability:

ZK-unfriendly activations:   ReLU, GELU, Softmax (expensive comparisons)
ZK-friendly activations:     Polynomial activations like x², x³
                              (pure algebraic — zero extra constraints)

Trade-off: Polynomial activations are slightly less expressive
           than ReLU, but massively cheaper to prove

Research into architectures that sacrifice a small amount of accuracy for orders-of-magnitude cheaper proving is genuinely promising. For many applications (classification, regression), the accuracy trade-off is acceptable.

Optimistic zkML

A hybrid approach: run the model normally, commit to the output on-chain. Only generate a ZK proof if someone challenges the output.

Normal case (99.9% of the time):
  → Run model off-chain
  → Post commitment to output
  → No proof generated
  → Save enormous compute

Challenge case (0.1% of the time):
  → Challenger disputes an output
  → Prover generates ZK proof for disputed computation
  → Smart contract verifies proof
  → Honest party wins, dishonest party loses stake

This is essentially the optimistic rollup model applied to ML inference. Much cheaper in the common case. Weaker guarantee (outputs aren't immediately final). But practical today for many use cases.


The Honest State of zkML in 2026

Let me be direct about where things actually stand:

What works today:
  ✅ Small classification models (MNIST, CIFAR-10 scale)
  ✅ Logistic regression and linear models
  ✅ Tree-based models (gradient boosting, random forests)
  ✅ Embedding lookups (proving a specific embedding was retrieved)
  ✅ Specific transformer components in isolation (one attention head)
  ✅ Quantized INT4 models on specialized hardware

What's coming (1-3 years):
  🔄 Small transformers (BERT-tiny, DistilBERT scale)
  🔄 zkML with hardware accelerators (GPU/FPGA provers)
  🔄 Recursive proof aggregation for larger models
  🔄 ZK-friendly neural architectures with acceptable accuracy

What's a decade away (maybe):
  ⏳ GPT-2 scale models in practical time
  ⏳ Any frontier LLM (GPT-4, Claude, Gemini scale)
  ⏳ Real-time zkML inference at production scale

The fundamental physics haven't changed. Proving a 175B parameter model requires proving trillions of constraints. Even with 1000× hardware improvement, we're looking at a decade before that's practical.

But here's the thing: zkML doesn't need to work for frontier models to be transformative. The use cases that matter most — fair lending models, medical diagnosis verification, on-chain AI agents, compliance verification — mostly involve models with millions of parameters, not billions.

The 10M parameter sweet spot is achievable today. And that covers an enormous amount of real-world AI.


The Complete ZK Proofs Picture

We started this series with a cave analogy. We end at the frontier of cryptography and AI.

Here's the full map of everything we covered:

PART 1 — FOUNDATIONS
├── Why ZK proofs exist (the information gap)
├── Ali Baba's Cave (the intuition)
├── Three properties: Completeness, Soundness, Zero-Knowledge
├── The Simulator Argument (the formal definition)
├── Sigma Protocols + Schnorr (the math)
└── Fiat-Shamir (making it non-interactive)

PART 2 — PROVING COMPUTATION
├── Arithmetic Circuits (programs as math)
├── R1CS (formalizing constraints)
├── QAP (constraints as polynomials)
├── KZG Commitments (the heart of SNARKs)
├── Trusted Setup (SNARKs' original sin)
├── STARKs (the trustless alternative)
├── SNARKs vs STARKs (the full trade-off)
├── ZK Rollups (the full architecture)
└── ZK vs Optimistic Rollups

PART 3 — ZK MEETS AI
├── Why zkML matters (the AI trust crisis)
├── Why it's hard (float, activations, scale, memory)
├── EZKL (the production zkML library)
├── Working MNIST classifier proof
├── Circom circuits for neural operations
├── Research frontier (recursion, hardware, architecture)
└── Honest state of the field in 2026

The One Thing To Remember From This Series

Zero-Knowledge Proofs solve a problem that seems impossible: convince someone you know something without telling them what you know.

They do it by making cheating statistically impossible, and by proving that fake transcripts are indistinguishable from real ones — which means real transcripts contain nothing worth extracting.

Applied to blockchain: you can verify millions of transactions with a 200-byte proof.

Applied to AI: you can prove a model ran correctly without revealing the model.

We're at the beginning of understanding what that means. The math has been there for decades. The engineering is catching up. And the applications — trustless AI, private computation, verifiable systems — are going to matter more as AI becomes more powerful and more central to decisions that affect people's lives.

If you've read all three parts: you now understand ZK proofs at a depth that most engineers — including most blockchain engineers — don't have.

That's the moat.


I'm Niranjan — Full Stack & Web3 Developer at Alkimi Exchange, M.Sc. student in Data Science & Generative AI. Writing about what I'm actually learning, not what sounds impressive.

Follow me on X / Twitter | Read the full series on Hashnode


This concludes the Zero-Knowledge Proofs series. Part 1: The Proof That Reveals Nothing Part 2: SNARKs vs STARKs: The Great ZK Showdown Part 3: Can You Prove an AI Ran Correctly?

B
BlastSlot1mo ago

What makes zkML interesting isn’t just the cryptography — it’s the shift toward verifiable computation becoming part of the AI stack itself.

Most people still treat AI outputs as black boxes: “the model said this, so trust it.”

But as AI starts handling financial decisions, autonomous agents, identity systems, moderation, healthcare, and infrastructure, blind trust stops scaling.

That’s why zkML matters even in its current limited form.

The important takeaway from your piece is the honesty around constraints. A lot of people talk about zkML like GPT-4 proofs are right around the corner, when the reality is much messier:

  • floating point incompatibility
  • activation function complexity
  • proving costs
  • memory bottlenecks
  • quantization tradeoffs

Those problems are real.

Still, the practical middle ground is probably where the first adoption wave happens:

  • smaller specialized models
  • compliance verification
  • private inference
  • on-chain agents
  • proving specific components instead of entire frontier models

That alone is a massive shift.

The interesting parallel is that blockchain itself evolved the same way. Early expectations were unrealistic, then infrastructure slowly improved underneath the surface until practical use cases started emerging.

Feels similar here.

Also worth noting that privacy infrastructure across Ethereum is evolving at the same time — shielded pools, frame transactions, keyed nonces, private execution research. zkML and privacy-preserving computation may eventually converge into a much larger verifiable AI ecosystem than people currently realize.

The frontier isn’t “AI on blockchain.” It’s probably “cryptographically verifiable computation everywhere.”

That’s the deeper theme underneath all of this.