ERC-8274: AI Inference Proof Verification

Jimmy —

Tiago just answered your question better than any spec prose could. The infrastructure is live. The bounty scenario maps cleanly to the existing stack:

The settlement contract calls IProofVerifier.verify(input_hash). The verifier confirms the input_hash appears in the OCP Recorded event and the ERC-8263 commitment matches. If both pass, funds release. No trusted intermediary. Just public RPC and the on-chain event log.

What you named as the open question — whether the abstract interface is rich enough to carry what the consumer needs regardless of what’s behind it — is exactly the right test for ERC-8288. The bounty scenario is a good one to anchor against because it forces every layer to do its job in sequence. If IProofVerifier.verify() can carry the settlement condition cleanly without caring whether OCP or something else produced the proof, the abstraction holds.

Run it live with Tiago. That’s the proof of concept the ERCs need.

— Damon

2 Likes

Tiago —

Agreed on both counts. WYRIWE defines what goes into the commitment. IProofVerifier abstracts over what backs the verification. The two don’t need to know about each other — that’s the composability guarantee.

The bounty walkthrough you just posted is the clearest end-to-end demonstration of the stack I’ve seen. If you can run it live with Jimmy’s settlement contract calling IProofVerifier.verify(), that’s the moment the ERCs become real.

— Damon

2 Likes

Ran it live.

BountySettlement deployed on Base Sepolia:
0x57fe09a6Eb8d5741b24fF640AA8Bc4D2010B93D7
https://sepolia.basescan.org/tx/0x867b2c58e09509a7dddeead926dad3fbf9713c6c1fafb9b1a1a44cc46f65d343

End-to-end flow:

  1. Agent executes → gateway anchors input_hash on OCP (L3) and produces an EIP-712 InferenceAttestation signature (L4)

  2. Anyone can fetch the proof: GET gateway.ensub.org/agent/verify/:inputHash → returns all attestation struct fields + signature

  3. Claimant calls claimBounty(...) on-chain with the struct fields + L4 signature

  4. Contract reconstructs the EIP-712 digest, recovers the signer, checks it matches the registered gateway attestor — no oracle, no intermediary

  5. Bounty releases

Post tx: https://sepolia.basescan.org/tx/0x30721ad6b0ff540b9e54438ec7c3c06e2c5485ed5493bade321f0debf4af217d
Claim tx: https://sepolia.basescan.org/tx/0x2780f94d11ad3766e7d370b1016d3ba917933f8111ddd42d3fcab2226cd380e4 :white_check_mark:

Live verify endpoint (public, no auth):
https://gateway.ensub.org/agent/verify/758d61f26a44448384e5c4468a0dcb7a2abe456067b0f7b505bc28b9411fe931

The contract hardcodes GATEWAY_ATTESTOR for the PoC. The production path calls registry.getAgentWallet(agentId) the same ERC-8004 lookup that already resolves to the gateway key — making the signer check trustless through the registry rather than a hardcoded address.

@JimmyShi22 IProofVerifier.verify() can wrap this pattern directly. The input_hash is the shared key between the off-chain execution record and the on-chain settlement. If your settlement contract calls our deployed verifier, this is the live stack end-to-end.

@Damonzwicker WYRIWEIProofVerifier → settlement: the interfaces compose cleanly. OCP is the trustless floor, EIP-712 is the infrastructure layer on top.

Contract source: https://gist.github.com/TMerlini/bf3abd30c332cccb257d0e5bdff1ff95

2 Likes

@TMerlini @VincentWu @JimmyShi22

This is the moment.

BountySettlement live on Base Sepolia. OCP as the trustless floor, EIP-712 as the infrastructure layer, IProofVerifier wrapping the pattern directly. The input_hash as the shared key between off-chain execution and on-chain settlement — no oracle, no intermediary, just public RPC and the on-chain event log.

The stack isn’t theoretical anymore. It just settled a bounty.

@JimmyShi22 — your interface question is answered. The abstraction holds end-to-end.

— Damon

3 Likes

Quick update for everyone: ERC-8274 now has an official number — the editors assigned it, so the PR is live as ERC-8274: AI Inference Proof Verification Interfaces. Really glad this thread gave it the right context to land well. Thank you all — @Damonzwicker, @TMerlini, @VincentWu — the discussion here shaped the spec in ways I couldn’t have gotten to alone.

https://github.com/ethereum/ERCs/pull/1771

2 Likes

@TMerlini — the BountySettlement deployment is a fantastic piece of work. Seeing the full stack running live on Base Sepolia — ERC-8004 identity, your input trust layer with the triple-hash scheme, OCP verification, and ERC-8263 commitment all wired together end-to-end — makes the whole architecture feel much more concrete and approachable than any spec text alone could. That kind of hands-on demonstration is genuinely valuable for everyone trying to understand how these pieces fit.

I’d love to see if we could polish this up a bit and bring it in as a reference implementation example for our ERC — even a minimal walkthrough showing how a contract would call verify() against a deployment like BountySettlement would give implementors a real starting point. Happy to collaborate on shaping that however works best for you.

@VincentWu — looking forward to v0.2! The profile system you’re building into ERC-8263 sounds like exactly the right move, especially with WYRIWE becoming a formal profile. Once it’s ready I’d love to make sure the cross-references between ERC-8263 and ERC-8274 are as tight as possible — the write/read path alignment should read as one coherent story for implementors.

3 Likes

Jimmy —

Congratulations on ERC-8274. Well earned — the spec is cleaner for having been stress-tested against a live stack before it went to the editors.

Tiago’s BountySettlement is exactly the kind of reference implementation ERC-8274 needs. The input_hash as the shared key between off-chain execution and on-chain settlement is the pattern that makes verify() concrete for implementors.

Looking forward to seeing the cross-references between ERC-8274 and ERC-8263 v0.2 tighten up. The write/read path as one coherent story is the right framing.

— Damon

2 Likes

@JimmyShi22 — congratulations on ERC-8274. The number being assigned
before v0.1 publication is the right kind of signal from the editors.

On v0.2: WYRIWE lands as a profile in the proofHash Constructions
appendix, with the IDENTITY_SENTINEL branching invariant codified
explicitly so verifiers don’t fail silently on pass-through executions.
Core contract stays opaque bytes32 — the profile carries the semantics,
not the contract surface.

Cross-references between ERC-8263 v0.2 (write side) and ERC-8274 (read
side) feel right to tighten in a follow-up revision once 8274 v0.1 is
out, rather than coupling timelines now. The write/read story should
read as one coherent loop for implementors — fully agree on the framing.

Tiago’s BountySettlement deployment is exactly the kind of end-to-end
that makes the stack legible. Glad to see it cited as ERC-8274
reference territory.

— Vincent

1 Like

Hey Vincent —

One thing came up while digging into the ERC-8004 spec that might be worth a note in ERC-8263 v0.2: ERC-8004’s agentId is a plain uint256 (ERC-721 tokenId), but agentIdScheme 0x01 (REGISTRY) in ERC-8263 encodes it as bytes32, which requires left-zero-padding when crossing between the two.

It’s not a blocker — the conversion is straightforward — but implementors who aren’t aware of it could run into subtle bugs when encoding and decoding across the boundary. Might be worth a short note in the v0.2 spec or the Composition Note, just so it’s explicit rather than something people have to discover on their own.

Happy to help draft the wording if useful!

1 Like

Congratulations on ERC-8274, well deserved, and the number being assigned before v0.1 publication says a lot. :slightly_smiling_face:

Happy for BountySettlement to serve as reference territory. The verify endpoint is public and returns everything a settlement contract needs to call IProofVerifier.verify():

GET https://gateway.ensub.org/agent/verify/:inputHash

Returns: input_hash, raw_input_hash, sanitization_pipeline_hash, output_hash, manifest_hash, agent_id, registry, l4_signature, l4_timestamp, l3_tx.

The input_hash is the shared key — claimant fetches the struct fields from the endpoint, submits them on-chain, contract recovers the EIP-712 signer and verifies. BountySettlement source:
https://gist.github.com/TMerlini/bf3abd30c332cccb257d0e5bdff1ff95

Claim tx on Base Sepolia (live proof):
https://sepolia.basescan.org/tx/0x2780f94d11ad3766e7d370b1016d3ba917933f8111ddd42d3fcab2226cd380e4

Happy to shape the walkthrough together once v0.1 is out, keep it minimal, let the working code speak.

TMerlini / dinamic.eth

1 Like

Thanks @TMerlini — the gateway endpoint makes the oracle pattern very concrete, and the live claim tx is exactly the kind of working evidence that makes a spec credible.

Tagging @Damonzwicker @VincentWu @TMerlini and the broader thread — the interface is feeling clean at this point, and I’d love to get a few open questions settled before v0.1 goes out. Would genuinely value everyone’s perspective:


1. Input/Output Encoding — bytes32 hash or raw bytes?

Current design uses bytes32 inputHash and bytes32 outputHash. This keeps the interface minimal and gas-efficient, but pushes the hashing convention off-spec — each backend has to agree on what gets hashed and how. Raw bytes would let backends inspect content directly and avoid a separate hashing step, at the cost of higher calldata and new encoding questions. No strong view here yet — curious what feels right to people who are actually building the backends.

2. Input Segmentation — single input or split into systemPrompt / userPrompt?

My rough take: this only really matters for chat-style models where system and user context are structurally distinct. For non-chat inference (image, audio, structured data), the split doesn’t map cleanly. Splitting at the interface level would add expressiveness for one class of models at the cost of generality for the rest. Leaning toward keeping it as a single field, but would love to hear if anyone has a use case that cuts the other way.

3. Extension Fields — optional bytes calldata extra, or leave extensibility to proof?

Should the interface define an optional metadata field (model version, timestamp, session ID, etc.) that backends can use without touching the base interface? The alternative is to encode any extra context inside the proof bytes, keeping the interface flat. Tradeoff is between ergonomics for consumers vs. keeping the surface area minimal.

4. Naming Governance — self-assigned {system}/{variant}/{version} or a lightweight off-chain registry?

proofProfile() currently relies on self-assigned strings. Sufficient for now, but as more backends register, collisions become a real risk. Is a minimal off-chain name registry worth coordinating, or is that premature overhead at this stage?


On reference implementations: @TMerlini’s BountySettlement + gateway endpoint is a natural first example for the oracle/attestation pattern. For the spec to be complete, it would also benefit from examples showing how the interface composes with ERC-8183 (evaluator-side verification) and ERC-8004 (agent identity + validation registry) — both have natural integration points, and concrete examples there would make the standard a lot more actionable for implementors. Planning to include these in the PR (Add ERC: AI Inference Proof Verification by JimmyShi22 · Pull Request #1771 · ethereum/ERCs · GitHub) before v0.1.

2 Likes

Answering from the live stack, these are decisions we had to make building the gateway:

1. bytes32 vs raw bytes: Stay with bytes32. The hash is computed off-chain before the transaction, having the contract recompute it from raw bytes adds gas with no trust benefit, since a malicious caller can submit any bytes anyway. Keep the interface minimal, let the profile define what gets hashed and how.

2. systemPrompt / userPrompt split: Keep it flat. The split only matters for chat-style models and belongs in the proof profile, not the interface. Our WYRIWE scheme handles this without interface-level segmentation — raw_input_hash covers the full input, the sanitization pipeline defines what gets through. If the interface has two input fields, zkML verifiers and non-chat agents are suddenly misaligned with the type.

3. Extension fields vs proof bytes: Encode extras in proof. ERC-8263 made the same call with aux - opaque bytes, profile-defined semantics, no canonical meaning at the contract level. Optional metadata fields in the interface create versioning problems the moment two profiles disagree on what the field means. Flat interface + rich proof bytes is the right split.

4. Profile naming collisions: keccak256(abi.encodePacked(name, version)) as the profile ID. No off-chain registry needed for v0.1 - collision risk is theoretical at this stage and a registry is overhead that slows adoption. You can always add governance later; removing a required registry is much harder.

2 Likes

Tiago covered the live-stack view precisely. One thing worth adding on question 1 from the OCP side:

bytes32 isn’t just a gas decision — the digest is the portable unit. It’s what makes independent verification possible across chains and implementations. recompute → compare → confirm inclusion only works if the thing being compared is the digest, not raw bytes that require re-hashing inside the contract.

The portability guarantee lives at the hash boundary. Keep it there.

— Damon

2 Likes

Quick update: ERC-8263 v0.2 is live on PR #1748 — all 9 CI checks green.

What’s in v0.2 (all informative under Security Considerations, no
contract surface changes):

  • §Compatibility with ERC-8004 (scheme 0x01 bridge encoding)
  • §Compatible Identity Registries (IAgentWalletResolver SHOULD interface)
  • §Independent Verification (chain-state-only five-step path)
  • §OCP Boundary Note (write-side / read-side separation)
  • §Recommended proofHash Constructions (three profiles, opt-in)

Confirming the points from Round 1:

  • WYRIWE is documented as a profile under §Recommended proofHash
    Constructions (“Input-provenance with identity sentinel”), not as a
    normative contract requirement.
  • The IDENTITY_SENTINEL pass-through invariant is in that same profile:
    verifiers MUST branch on the sentinel, with chain-layer identity
    resolution via (agentIdScheme, agentId) when the sentinel is present.
  • ERC-8263 ↔ ERC-8274 cross-references are intentionally deferred to a
    v0.3 follow-up so v0.2 ships independently of ERC-8274 v0.1 publication
    timing.

Happy to coordinate the v0.3 cross-reference work once ERC-8274 v0.1
lands. The L5 verifier-side interface in ERC-8274 (IProofVerifier
consuming inputHash / proofHash as a black box) reads cleanly against
the L4 commitment surface ERC-8263 defines.

3 Likes

Congratulations Vincent — this is the right shape for v0.2. Informative additions only, no contract surface changes, clean separation between the normative anchor and the profile layer above it.

The §OCP Boundary Note lands exactly as discussed. The write-side / read-side separation is the constraint that keeps the stack composable as it grows.

Looking forward to the v0.3 cross-reference work once ERC-8274 v0.1 lands.

— Damon

2 Likes

@Damonzwicker @TMerlini @VincentWu — wanted to mark a small milestone and say thank you. The conversations in this thread shaped the spec in ways that wouldn’t have happened without this community, and genuinely grateful for the time and thought each of you put in.

v0.1 of ERC-8274 is now up as PR #1771 in the ethereum/ERCs repository.

This is very much a first draft — feedback and pushback are both welcome. Would love your eyes on it whenever you have a moment, and hoping to shape v0.2 around what comes back from this thread. If there are any cross-references you’d like added on your end (e.g. pointing from ERC-8263 or other specs toward ERC-8274), just let me know and I’m happy to coordinate.

Really appreciate everything that went into getting here — this has been a genuinely collaborative thread.

2 Likes

Congratulations on getting v0.1 out Jimmy, :grinning_face: this has been a great thread to be part of and this is a great foundation for the standard.

For the WYRIWE reference: the formal ERC draft and Ethereum Magicians discussion thread are now live if useful for cross-referencing:

The inputHash field in IProofVerifier.verify() maps directly to WYRIWE’s input_hash — same key, same keccak256 construction. Happy to coordinate cross-references once the WYRIWE PR is submitted to ethereum/ERCs.

2 Likes

Congratulations Jimmy — v0.1 is a clean foundation and the interface shape held up well through the thread.

I’ll review PR #1771 and flag anything on the OCP alignment side. On cross-references — once ERC-8263 v0.3 lands with the ERC-8274 pointer, OCP’s spec can reference ERC-8274 as the contract-facing interface layer above it. Happy to coordinate timing with you and Vincent.

Damon

1 Like

Tiago — WYRIWE as a standalone ERC is exactly the right move. The inputHashinput_hash mapping makes the cross-reference between ERC-8274 and WYRIWE clean and explicit. Following the thread now.

— Damon

2 Likes

@TMerlini @Damonzwicker — quick note on cross-references, since it came up while working through the CI checks.

The ethereum/ERCs validator (eipw) has a markdown-rel-links rule that only allows relative links within the repo — external URLs (including ethereum-magicians.org discussion threads and external GitHub repos) aren’t permitted in the body of a spec. This affects both the WYRIWE reference in the Input Provenance section and the OCP reference in the Rationale — both are currently plain text without hyperlinks. Not ideal, but the right thing to do within the constraints.

The good news is that once ERC-8263 (PR #1748) and WYRIWE both land in ethereum/ERCs, we can add proper relative links between all three specs (./eip-8263.md, ./eip-XXXX.md) and everything will be fully cross-referenced in a way the tooling accepts. Looking forward to that moment — feels like a natural point to do a proper v0.2 pass across all of them.

@Damonzwicker — one open question on the OCP side: since OCP doesn’t have an ERC number yet, there’s no relative link path available under the current tooling rules. For now it’s referenced as plain text (damonzwicker/observation-commitment-protocol) in the Rationale. If there are plans to submit OCP as an ERC, that would be the cleanest resolution. Otherwise, curious whether you have a preference for how it should be cited — happy to follow your lead on this.

@TMerlini — also, the “Composition with ERC-8183” and “Composition with ERC-8004” examples in the Reference Implementation section are fairly preliminary — they sketch the integration pattern but are far from production-quality. Would really appreciate your eyes on those if you have a moment. Any thoughts on how the composition should actually be structured, or where the current examples fall short, would be genuinely helpful for v0.2.

1 Like