0G TeeML inference
July 29, 2026 · View on GitHub
✅ UPDATE — fully recomputed on a genuine enclave (0G Compute mainnet, glm-5.2). 0G gave us mainnet access; we ran the broker path (
processResponse) on a real glm-5.2 action and recomputed the entire chain — notee_verifiedflag.node verify-enclave.mjs(readsglm52-enclave.json) reproduces all of it: EIP-191 signer recovery →0xA46EA4…,sha256(request)==H(req)andsha256(response)==H(resp)(both client-recomputable — a genuine enclave signs the plainH(req):H(resp), unlike the relay), the TDX quote's RTMR event-log replay (SHA-384, 4/4), andreport_data == signer == on-chain registry teeSignerAddress. The chain: live response ← signed by →0xA46EA4← attested by → the enclave's TDX quote ← declared by → the on-chain 0G registry. Frozen as conformance profiletee-inference-enclave.v0(recompute-kit#2, 9/9). The relay analysis below stands as the honest baseline; this is what a genuine enclave lets you do.✅ + the quote's HARDWARE root of trust, recomputed too (Intel PCS lane, dcap-qvl).
node verify-dcap.mjsparses the PCK cert chain embedded in the quote and verifies each signature up to the Intel SGX Root CA — pinned to Intel's known key44a0196b…74d3— then the QE-report signature (PCK leaf), the attestation-key↔QE binding (report_data), and the TD-quote signature (att key). So the quote is provably produced by a genuine Intel-provisioned TDX part, checked to Intel's root — no vendor SDK, no trusted verifier. Same core runs client-side in the browser on the live panel (@peculiar/x509+ Web Crypto). The/verifyenclave panel is now 9 recomputed-green + 1 residual — the only residual left is the known-good image (MRTD == 0G's published glm-5.2 measurement), pending 0G publishing that measurement. TCB-status / CRL freshness (Intel PCS collateral) stays a documented residual.
Part 1 — the relay baseline (Galileo)
One real signed inference on the 0G Galileo TeeML provider, pulled from the SDK's actual
processResponse source path (@0gfoundation/0g-compute-ts-sdk → broker/response.js → broker/verifier.js)
— not a spec written from the outside. verify-check1.mjs re-runs the recovery from teeml-sample.json so you
can reproduce it yourself: don't trust — recompute.
- provider
0xa48f01287233509FD694a22Bf840225062E67836(qwen/qwen2.5-omni-7b) - signer
0x83df4B8EbA7c0B3B740019b8c9a77ffF77D508cF - chain 0G Galileo (16602)
The verify path (from source)
// response.js — ResponseProcessor.processResponse
const ResponseSignature = await Verifier.fetchSignatureByChatID(svc.url, chatID, svc.model); // GET {url}/v1/proxy/signature/{chatID}?model={model} -> { text, signature }
return Verifier.verifySignature(ResponseSignature.text, ResponseSignature.signature, signingAddress);
// verifier.js
static verifySignature(message, signature, expectedAddress) {
const messageHash = ethers.hashMessage(message); // EIP-191 personal_sign prefix
const recoveredAddress = ethers.recoverAddress(messageHash, signature);
return recoveredAddress === expectedAddress;
}
So: preimage = ResponseSignature.text, hashed EIP-191 (ethers.hashMessage), signature is 65-byte
secp256k1 (r,s,v), recovered address must equal the TEE signer.
The signed preimage is a structured commitment (NOT the answer)
H(request) : H(response) : providerType : providerIdentity : H(session)
captured value:
c8d4932769c4be14a5c4614ff1c31dee79aef1bd842d656fe1f39992d247fb51:d2fe539f9eaec3aef9f01c8a19a6dd43816d74a1d5e189e418c906b1769fef4a:centralized:aliyun:cc7c08805b2b0c44f53faae5d917ac07367fd9112971ca2405b8fa2e4b0acd51
- encoding: ASCII,
:-joined; hashes are lowercase-hex sha256. - domain separation: only EIP-191's
"\x19Ethereum Signed Message:\n"+lenprefix. No app-specific tag. - anti-replay: chatID / zg_res_key is NOT in the signed bytes — it is only the fetch key for the signature. Replay-binding is transport-level (the sig is retrievable only by the chatID holder, briefly), not cryptographic.
- canonicalization: the broker hashes as
sha256(JSON), not RFC-8785 JCS — confirmedH(response) == sha256(JSON.stringify(completion)). So the TEE's digests are in the broker's scheme, distinct from therequest_jcs_sha256/response_jcs_sha256fields in the sample. Bind through the broker scheme, or prove the JCS↔broker-hash correspondence over the same bytes.
Preimage construction — traced to the SERVER source (not inferred)
The client SDK only verifies hashMessage(text); the text is built server-side
(0gfoundation/0g-serving-broker api/inference/internal/ctrl/signing.go signCentralizedRoutingProof
→ api/common/tee/tls.go FormatRoutingProofText):
text = requestSha256 : responseSha256 : providerType : providerIdentity : tlsCertFingerprint
sig = crypto.Sign(accounts.TextHash([]byte(text)), providerSigner) // EIP-191
requestSha256=sha256(reqBody)— reqBody is the body the broker forwards UPSTREAM (DashScope), enclave-internal bytes. Confirmed: no client canonicalization reproduces it (wire body / JCS / sorted-keys / +stream all miss). The broker signature over hash1 is established, but the client cannot verify the hidden forwarded body is byte-equal to its request → request binding is broker-asserted, not independently recomputable from the client vantage (distinct from a hardware attestation).responseSha256=sha256(respData)=sha256(JSON(completion))(established).tlsCertFingerprint= SHA256(upstream leaf TLS cert) — a routing proof, constant across independent inferences (same DashScope endpoint cert), NOT a session nonce. So it provides no anti-replay; combined withchatIDbeing absent from the preimage, there is no cryptographic replay binding at all.
Evidence class per check
| # | check | status on this provider |
|---|---|---|
| 1 | ecrecover(EIP-191(preimage)) == signer | RECOMPUTED ✅ — verify-check1.mjs recovers 0x83df…508cF |
| 2 | request/response digest binding | response RECOMPUTED ✅ (H(resp)=sha256(JSON(completion))); request needs the verbatim outgoing HTTP body (one capture detail) |
| 3a | signer ↔ provider identity | recomputable via the 0G provider registry (0x83df ↔ 0xa48f) |
| 3b | raw dstack enclave quote | NOT AVAILABLE — this provider is a relay (see below) |
The finding that matters: this provider has no enclave attestation
The provider's own /v1/proxy/attestation/report returns, verbatim:
"LLM attestation report is not available for this provider. This service forwards to an upstream API without local TEE attestation."
The response headers confirm it (x-dashscope-call-gateway: true): the model runs on Alibaba Cloud
DashScope; 0xa48f is a signing relay, not an enclave. The preimage says so itself: …:centralized:aliyun:….
A scan of the entire Galileo TeeML population = 2 providers, neither an enclave: the aliyun relay above, and
0x4b2a (image-edit) whose attestation endpoint is a plain 404. So the raw dstack quote / independent
attestation parsing is not obtainable on Galileo today — blocked at the network level, not by effort. It needs
0G to point at (or stand up) a genuine-enclave TeeML provider / the Galileo TEE oracle.
So, stated precisely:
- TEE execution reported: yes. SDK verification reported: yes.
- Independent signature verification: ESTABLISHED (check 1 — reproduce with
verify-check1.mjs). - Independent request/response digest binding: response established, request pending the verbatim body.
- Independent attestation parsing: not establishable on Galileo today (no provider emits a quote).
For this provider, "TeeML" = a broker signature over its own digests of (request, response) + identity — not a hardware quote that the model ran in a sealed enclave. The recompute discipline caught a real overclaim in the wild. A conformance vector can carry checks 1–3 without collapsing them, shipping check-3b as an explicit "attestation unavailable (relay provider)" amber — never a green — until a genuine enclave provider exists.
Files
teeml-sample.json— the full artifact: preimage, 65-byte signature, the endpoint's raw{text, signature}, the JCS canonical forms + hashes, raw completion + response headers, and the "not available" attestation body.verify-check1.mjs—node verify-check1.mjs→ independently recovers the signer from the sample (check 1).capture-teeml.ts/scan-teeml.ts— how the sample and the provider scan were produced.