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:
- Runs inference via
@foundryprotocol/0gkit-compute. - Signs the inference receipt server-side:
digestJson(receipt)is hashed and signed withsignMessage(EIP-191 personal-sign); the signer is recovered viarecoverSignerand compared to the expected operator address. - Returns the signed receipt and a
verifiedboolean to the client. - The
SealedChatReact component renders ✓ signature verified whenverifiedistrue, or a clear failure badge otherwise. Verification happens server-side insidesealedInfer; the component reflects that result — it never callsverifyEnvelopedirectly.
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
| Variable | Example | Notes |
|---|---|---|
OG_COMPUTE_MODEL | neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8 | Model for inference (optional — provider default if omitted) |
OG_PRIVATE_KEY | 0x... | Operator key for signing inference receipts |
OG_RPC_URL | https://evmrpc-testnet.0g.ai | 0G chain RPC endpoint |
OG_ATTESTOR_ADDRESS | 0x... | 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-oracle — OG_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:
verifiedis a signed-receipt check — the expected operator key signed this exact receipt — not a TEE-quote verification.sealedInfernever throws on a tampered signature; it returnsverified: falseso the badge shows the real outcome (never hardcoded green).
Tiers
- lib —
lib/sealed.ts(portableSealedInference,SealedEnvelopetype,sealedInferhelper). - adapters — one per base (
app/api/sealed/route.tsfor Next.js,src/routes/sealed.tsfor Hono,src/tools/sealed.tsfor MCP). - ui —
components/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.