A minimal end-to-end pattern for cryptographically attributable AI inference – no zkML, no TEEs, just signatures + datachain storage.
The Problem: Ephemeral AI Outputs
Every LLM call today produces a response that vanishes into chat history. You can't prove:
- Which agent identity generated it
- Which model configuration produced it
- That the prompt-response pair wasn't fabricated later
- The record will survive provider outages or policy changes
Verifiable AI fixes this: every inference becomes a signed, immutable, publicly auditable artifact.
But most "verifiable AI" demos require zkML provers, TEE enclaves, or custom consensus. What if you want verifiable AI today with tools you already know?
The Minimal Pattern: 3 Primitives
1. Gaia Node → OpenAI-compatible decentralized inference
2. Ethers Wallet → Agent identity + ECDSA signature
3. Irys → Immutable datachain storage + proofs
Total dependencies: openai, @irys/upload, ethers. That's it.
Here's the complete demo:
require('dotenv').config();
const OpenAI = require('openai');
const { Uploader } = require('@irys/upload');
const { Ethereum } = require('@irys/upload-ethereum');
const { ethers } = require('ethers');
const GAIA_NODE_URL = "https://0x3b70c030a2baaa866f6ba6c03fde87706812d920.gaia.domains/v1";
const GAIA_API_KEY = "gaia";
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function main() {
// PHASE 1: AGENT EXECUTION
const provider = new ethers.JsonRpcProvider("https://arb1.arbitrum.io/rpc");
const agentWallet = new ethers.Wallet(PRIVATE_KEY, provider);
console.log(`🆔 Agent: ${agentWallet.address}`);
const client = new OpenAI({ baseURL: GAIA_NODE_URL, apiKey: GAIA_API_KEY });
const prompt = "What is the primary function of a blockchain?";
const completion = await client.chat.completions.create({
messages: [{ role: "user", content: prompt }],
model: "llama",
});
const payloadObj = {
timestamp: new Date().toISOString(),
agent_id: agentWallet.address,
model: completion.model,
prompt: prompt,
response: completion.choices[0].message.content
};
const payloadString = JSON.stringify(payloadObj);
const signature = await agentWallet.signMessage(payloadString);
const irys = await Uploader(Ethereum).withWallet(PRIVATE_KEY);
const receipt = await irys.upload(JSON.stringify({
verifiable_data: payloadString,
signature: signature,
signer_address: agentWallet.address
}), {
tags: [{ name: "Content-Type", value: "application/json" }, { name: "App-Name", value: "Gaia-Verifiable-Demo-v1" }]
});
const proofURL = `https://gateway.irys.xyz/${receipt.id}`;
console.log(`🎉 Proof: ${proofURL}`);
// PHASE 2: PUBLIC VERIFICATION
await sleep(3000);
const response = await fetch(proofURL);
const downloadedJson = await response.json();
const recoveredAddress = ethers.verifyMessage(downloadedJson.verifiable_data, downloadedJson.signature);
if (recoveredAddress === downloadedJson.signer_address) {
console.log("✅ CRYPTOGRAPHIC PROOF VALID");
const parsedData = JSON.parse(downloadedJson.verifiable_data);
console.log(`Question: ${parsedData.prompt}`);
console.log(`Answer: ${parsedData.response.substring(0, 60)}...`);
}
}
main();
Live Demo Output
🚀 STARTING VERIFIABLE AI DEMO (END-TO-END)
--- PHASE 1: AGENT EXECUTION ---
🆔 Agent Identity: 0xbDe71618Ef4Da437b0406DA72C16E80b08d6cD45
🤖 Agent is querying Gaia Node...
✅ Gaia Responded: "The primary function of a blockchain is ..."
✍️ Agent is signing the record...
🎉 Upload Complete! Proof URL: https://gateway.irys.xyz/4mjffbHJnQcr7uJQuS3F1dWSJiswu7RuZPh7jS6YpfCr
--- PHASE 2: PUBLIC VERIFICATION ---
🕵️ VERIFICATION RESULTS:
Claimed Signer: 0xbDe71618Ef4Da437b0406DA72C16E80b08d6cD45
Recovered Signer: 0xbDe71618Ef4Da437b0406DA72C16E80b08d6cD45
✅ PASS: CRYPTOGRAPHIC PROOF VALID
--- TRUSTED DATA CONTENT ---
Question: What is the primary function of a blockchain?
Answer: The primary function of a blockchain is to serve as a decent...
The Verifiable Artifact on Irys
Click this proof URL to see the raw record:
{
"verifiable_data": "{\"timestamp\":\"2025-12-09T17:24:29.632Z\",\"agent_id\":\"0xbDe71618Ef4Da437b0406DA72C16E80b08d6cD45\",\"model\":\"Mistral-Small-3.1-24B-Instruct-2503-Q5_K_M\",\"prompt\":\"What is the primary function of a blockchain?\",\"response\":\"The primary function of a blockchain is to serve as a decentralized...\"}",
"signature": "0x17859ea71554c3d2872452eea83a99a81d6064483d37ff4fe6eef3d59d08c9012a05162b1a5eaad5fac0f677f2a54101d9c0c4deee74528a54b74d2f5e26fe091c",
"signer_address": "0xbDe71618Ef4Da437b0406DA72C16E80b08d6cD45"
}
What Any Verifier Can Prove
Given only the Irys URL, anyone can mathematically confirm:
1. FETCH record from datachain → Irys guarantees integrity via PoW/PoS consensus
2. RECOVER signer: ethers.verifyMessage(verifiable_data, signature) → 0xbDe71618...
3. MATCH signer_address → ✅ Agent 0xbDe716... endorsed this exact payload
4. PARSE verifiable_data → model=Mistral-Small-3.1-24B, prompt, response, timestamp
Guarantees provided:
| Property | How It's Ensured |
|---|---|
| Integrity | Irys datachain Merkle proofs + replication |
| Authenticity | ECDSA signature over exact JSON payload |
| Persistence | Irys economic guarantees (100+ yr availability) |
| Auditability | Public gateway + OpenAI-compatible replay |
What It Does NOT Prove (Yet)
This is honest verifiable AI, not magic:
- ❌ No model execution proof: Doesn't prove weights ran inside TEE/zkML
- ❌ No hardware attestation: Doesn't prove Gaia node ran on specific hardware
- ❌ No determinism: LLM may give different outputs on replay (non-deterministic)
- ❌ No input integrity: Doesn't prove prompt wasn't manipulated pre-inference
It's "verifiable interaction history", not "verifiable compute proof".
Why This Is Production-Ready Verifiable AI
Most AI agents need attributable outputs, not full zkML:
Trading Bot → "Did agent 0xabc execute strategy X at time T?"
RAG Agent → "Did domain expert node answer query Y?"
Orchestrator → "Which child agent produced response Z?"
Your pattern solves these 90% of cases with:
-
1-line integration:
client = new OpenAI({baseURL: gaiaNode}) -
1-line signing:
signature = await wallet.signMessage(payload) -
1-line storage:
receipt = await irys.upload(record)
Scaling to Stronger Verifiability
Same pattern, incremental upgrades:
1. TEE Gaia Node → Add "enclave_attestation" to payload
2. Deterministic LLM → Pin seed/temp for replay convergence
3. zkML Wrapper → Add "zksnark_proof" to payload
4. Onchain Settlement → Emit event with Irys receipt ID
The surface stays identical: sign → upload → share URL.
Get Started
npm init -y
npm i openai @irys/upload @irys/upload-ethereum ethers dotenv
echo "PRIVATE_KEY=your_arbitrum_key" > .env
node demo.js
Run your node: GaiaNet.ai
Read Irys docs: irys.xyz
This is verifiable AI you can ship today. No waiting for protocol wars.

Top comments (0)