0Gkitdocs↗ HomePlaygroundGitHub

sealed-inference

Signed AI inference with a verification badge driven by the real verify result. Each response is signed by the operator key (✓ signature verified — not TEE-quote), and the UI badge reflects the actual verification outcome — never hardcoded, never always-green.

What it does

The sealed-inference kit adds a verifiable chat or completion endpoint with a React badge component. On each request it:

  1. Runs inference via @foundryprotocol/0gkit-compute.
  2. Signs the inference receipt server-side: digestJson(receipt) is hashed and signed with signMessage (EIP-191 personal-sign); the signer is recovered via recoverSigner and compared to the expected operator address.
  3. Returns the signed receipt and a verified boolean to the client.
  4. The SealedChat React component renders ✓ signature verified when verified is true, or a clear failure badge otherwise. Verification happens server-side inside sealedInfer; the component reflects that result — it never calls verifyEnvelope directly.

Compatible bases

react-app · chat · tee-attested-api · mcp-agent

Apply

# scaffold-time
npm create 0gkit-app -- --kits sealed-inference

# add to an existing project
0g add sealed-inference

Environment variables

VariableExampleNotes
OG_COMPUTE_MODELneuralmagic/Meta-Llama-3.1-70B-Instruct-FP8Model for inference (optional — provider default if omitted)
OG_PRIVATE_KEY0x...Operator key for signing inference receipts
OG_RPC_URLhttps://evmrpc-testnet.0g.ai0G chain RPC endpoint
OG_ATTESTOR_ADDRESS0x...Expected signer address that recoverSigner checks against

Quick start

0g add sealed-inference

sealedInfer(deps, prompt, expectedSigner) runs inference, signs the receipt, verifies it against expectedSigner, and returns a verified boolean the UI badge reflects. The default wiring uses the same signed-receipt attestor as ai-oracleOG_ATTESTOR_ADDRESS is the expected signer:

import { Compute } from "@foundryprotocol/0gkit-compute";
import { digestJson } from "@foundryprotocol/0gkit-core";
import { fromPrivateKey } from "@foundryprotocol/0gkit-wallet";
import { recoverSigner } from "@foundryprotocol/0gkit-attestation";
import { sealedInfer, type Attestor } from "./lib/sealed.js";

const signer = await fromPrivateKey(process.env.OG_PRIVATE_KEY as `0x${string}`);
const compute = new Compute({ signer });

const infer = {
  async infer({ prompt, model }: { prompt: string; model?: string }) {
    const r = await compute.router({
      messages: [{ role: "user" as const, content: prompt }],
      ...(model ? { model } : {}),
    });
    return { output: r.output };
  },
};

const attestor: Attestor = {
  async sign(receipt) {
    const digest = digestJson(receipt);
    return { digest, signature: await signer.signMessage({ raw: digest }) };
  },
  async verify(receipt, signed, expectedSigner) {
    const match = digestJson(receipt).toLowerCase() === signed.digest.toLowerCase();
    const recovered = await recoverSigner({
      digest: signed.digest as `0x${string}`,
      signature: signed.signature as `0x${string}`,
    });
    return {
      ok: match && recovered.toLowerCase() === expectedSigner.toLowerCase(),
      signer: recovered,
    };
  },
};

const result = await sealedInfer(
  { infer, attestor, model: process.env.OG_COMPUTE_MODEL },
  "Summarize the 0G network in one sentence.",
  process.env.OG_ATTESTOR_ADDRESS!
);
console.log(result.text, result.verified); // verified: true | false

Honesty caveat: verified is a signed-receipt check — the expected operator key signed this exact receipt — not a TEE-quote verification. sealedInfer never throws on a tampered signature; it returns verified: false so the badge shows the real outcome (never hardcoded green).

Tiers

  • liblib/sealed.ts (portable SealedInference, SealedEnvelope type, sealedInfer helper).
  • adapters — one per base (app/api/sealed/route.ts for Next.js, src/routes/sealed.ts for Hono, src/tools/sealed.ts for MCP).
  • uicomponents/SealedChat.tsx (badge + chat UI), hooks/useSealedInference.ts (React hook for React bases only).

Honesty note

The attestation layer signs digestJson(receipt) via EIP-191 personal-sign (signMessage); verification recovers the signer via recoverSigner and compares it to the expected operator address. There is no TEE quote verification in the current stack. The Attestor interface is injected so a real TEE-quote verifier can slot in later. The badge reflects the server's verified result — it is never hardcoded green.