Harish Kotra

Dec 10, 2025 • 4 min read

Verifiable AI in 69 Lines: Signed Inference on Gaia + Irys

A minimal end-to-end pattern for cryptographically attributable AI inference – no zkML, no TEEs, just signatures + datachain storage.

Verifiable AI in 69 Lines: Signed Inference on Gaia + Irys

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

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.

Join Harish on Peerlist!

Join amazing folks like Harish and thousands of other builders on Peerlist.

peerlist.io/

It’s available... this username is available! 😃

Claim your username before it's too late!

This username is already taken, you’re a little late.😐

0

0

0