DEV Community

Cover image for Verifiable AI in 69 Lines: Signed Inference on Gaia + Irys
Harish Kotra (he/him)
Harish Kotra (he/him)

Posted on

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.

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
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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...
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Output Example

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?"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)