From 8542d926d1fd682959532f73114591f0fd98dcf0 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 15:56:32 +0800 Subject: [PATCH 01/40] Add draft ERC: Standard Interfaces for AI Inference Proof Verification --- ERCS/erc-draft-ai-inference-verification.md | 241 ++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 ERCS/erc-draft-ai-inference-verification.md diff --git a/ERCS/erc-draft-ai-inference-verification.md b/ERCS/erc-draft-ai-inference-verification.md new file mode 100644 index 00000000000..4e38e121a85 --- /dev/null +++ b/ERCS/erc-draft-ai-inference-verification.md @@ -0,0 +1,241 @@ +--- +eip: XXXX +title: Standard Interfaces for AI Inference Proof Verification +description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod) +author: JimmyShi22 (@JimmyShi22) +discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 +status: Draft +type: Standards Track +category: ERC +created: 2026-05-26 +requires: 165 +--- + +## Abstract + +This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: + +- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement to expose a uniform `verify()` entry point +- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use + +These interfaces define how verification is called and composed across proof systems, not how it is implemented internally. They sit at the horizontal coordination layer of the AI agent proof stack, above proof-system-specific contracts and below application logic. + +This standard is designed to compose with: +- **ERC-8004** for on-chain agent identity resolution +- **ERC-8263** for on-chain proof commitment (`anchor()`) +- **OCP (Observation Commitment Protocol)** for system-independent digest verification + +## Motivation + +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results (governance systems, DeFi protocols, autonomous agents) currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. + +Existing work addresses adjacent layers: + +- **ERC-8004** establishes agent identity but does not define verification interfaces +- **ERC-8263** defines a minimal `anchor()` interface for on-chain proof commitment but does not define how that commitment is verified across backends +- **OCP** defines a system-independent verification primitive (`recompute → compare → confirm inclusion`) but does not define backend-facing or consumer-facing interfaces + +The missing piece is a **common abstract interface** that lets proof backends be treated interchangeably by consumers, without requiring a central registry or coordinator contract. This ERC fills that gap. + +A central registry was the original framing of this proposal (see discussion thread). The discussion in posts #2–#10 surfaced a cleaner approach: abstract interfaces with no coordinator contract, following the same pattern as ERC-20's `transfer()`. Each consumer holds a direct reference to whichever `IProofVerifier` implementation it chooses, with no hub in between. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### IProofVerifier + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title IProofVerifier +/// @notice Interface for AI inference proof verification backends. +/// Implementations MAY support zkML, opML, TEE, oracle, multisig, +/// or any other proof system. +interface IProofVerifier { + /// @notice Verify an AI inference proof. + /// @param modelHash SHA-256 digest of the model weights or configuration + /// @param inputHash SHA-256 digest of the model input after sanitisation. + /// When no sanitisation pipeline is applied, + /// the corresponding sanitization_pipeline_hash MUST equal + /// the IDENTITY_SENTINEL defined in OCP: + /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea + /// @param outputHash SHA-256 digest of the model output + /// @param proof Backend-specific proof bytes (zkML proof, TEE attestation, etc.) + /// @return True if the proof is valid for the given hashes + function verify( + bytes32 modelHash, + bytes32 inputHash, + bytes32 outputHash, + bytes calldata proof + ) external view returns (bool); + + /// @notice Human-readable identifier for this proof backend. + /// RECOMMENDED format: "{system}/{version}", e.g. "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1" + function backendId() external view returns (string memory); +} +``` + +### IVerificationMethod + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title IVerificationMethod +/// @notice Interface for contracts that declare which proof verifier they use. +/// Consuming ERCs (governance, DeFi, agent systems) implement this to expose +/// their verification method in a discoverable, standardised way. +interface IVerificationMethod { + /// @notice Returns the proof verifier used by this contract. + function getVerifier() external view returns (IProofVerifier); + + /// @notice MUST be emitted when the verifier address changes. + event VerifierUpdated( + address indexed previousVerifier, + address indexed newVerifier + ); +} +``` + +### Composition with the AI Agent Proof Stack + +This ERC is designed to operate as Layer 5 of the following proof stack. Each layer is independently optional; the full attribution–commitment–verification chain requires all layers acting together. + +``` +Layer 1 ERC-8004 Agent on-chain identity +Layer 2 Input trust Sanitisation commitments, triple-hash scheme +Layer 3 OCP Portable, system-independent digest verification +Layer 4 ERC-8263 On-chain proof commitment via anchor() +Layer 5 This ERC IProofVerifier / IVerificationMethod abstract interfaces +``` + +**Write path (executed by the agent):** + +``` +1. input_hash = SHA-256(sanitised_input) // L2 output +2. output_hash = SHA-256(output) +3. ERC-8263.anchor(agentIdScheme, agentId, // L4 write + proofHash) // proofHash == input_hash +4. OCP.record(input_hash) // L3 commitment +``` + +**Read path (executed by the consumer):** + +``` +1. verifier = consumer.getVerifier() // L5 interface +2. valid = verifier.verify( // L5 interface + modelHash, inputHash, outputHash, proof) +3. Independently verify input_hash via OCP // L3 floor +``` + +### Semantic Alignment with ERC-8263 + +The `inputHash` parameter in `IProofVerifier.verify()` is semantically equivalent to the `proofHash` parameter in ERC-8263's `anchor()` function. Both refer to the SHA-256 digest of the sanitised model input (post-L2 processing). + +Implementations that use both interfaces MUST ensure these values are identical for the same inference event. + +### inputHash Requirements + +- `inputHash` MUST be the SHA-256 digest of the input as it was presented to the model after any sanitisation processing. +- When no sanitisation pipeline was applied, implementations MUST set `sanitization_pipeline_hash` to the IDENTITY_SENTINEL defined by OCP: + ``` + 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea + ``` + In this case, `inputHash` equals `raw_input_hash`. + +### OCP Anchoring + +Implementations of `IProofVerifier` SHOULD call `OCP.record(inputHash)` internally before returning from `verify()`, or commit `inputHash` to an OCP-compatible ledger asynchronously after the call. This ensures that the input commitment survives the proof system going offline and remains independently verifiable by any party. + +Whether this anchoring is synchronous or asynchronous, and on which chain, is implementation-defined. Cross-chain OCP compatibility (EVM and Solana) has been verified in practice (May 2026); the proof envelope schema requires no structural changes across chains. + +### ERC-165 Support + +Implementations SHOULD implement ERC-165 `supportsInterface()`: + +```solidity +function supportsInterface(bytes4 interfaceId) + external view returns (bool) +{ + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} +``` + +## Rationale + +### Abstract interfaces over a central registry + +A central coordinator contract introduces an unnecessary trust assumption: consumers must trust the registry itself has not been compromised. Abstract interfaces leave the choice of verifier to each consumer. Any contract can hold a reference to any `IProofVerifier` implementation directly — no hub required. This is consistent with OCP's design principle of minimising trust dependencies. + +### Why `backendId()` + +`backendId()` provides a human-readable identifier for off-chain tooling and on-chain event logs, allowing consumers to display "verified by zkML / TEE / opML" without parsing contract addresses. The `{system}/{version}` convention is recommended but not enforced; a formal registry of backend identifiers is left for a future ERC. + +### Why `proof` is opaque bytes + +Proof formats are intentionally backend-specific and evolve independently of this interface. Encoding format requirements belong in backend-specific ERCs or companion specifications, not in this interface layer. + +### Relationship to `IVerificationMethod` + +`IVerificationMethod` is a discovery interface. It allows indexers, wallets, and other contracts to determine which verifier a given contract uses without reading bytecode. The `VerifierUpdated` event provides an audit trail for verifier changes, which is security-relevant for consumers that hold significant value. + +## Backwards Compatibility + +No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. + +## Reference Implementation + +> To be contributed. Reference implementations for the following backends are anticipated: +> - zkML backend (RISC Zero / Bonsai) +> - opML optimistic backend +> - TEE backend (AWS Nitro / Intel TDX) +> - Oracle / multisig backend + +Live reference implementation of the full L1–L4 stack is available at `gateway.ensub.org` (ERC-8004 + input trust layer, by TMerlini / dinamic.eth). L5 integration is pending. + +## Open Questions + +The following questions are open for contributor input before this ERC is finalised. Contributors are welcome to open a PR against this draft or reply in the discussion thread. + +**Q1: Should OCP anchoring be SHOULD or MUST? (for @Damonzwicker)** + +The current draft uses SHOULD for `OCP.record(inputHash)`. Arguments for MUST: without it, the L3 portability guarantee is absent and the full stack is broken. Arguments against: async anchoring patterns (as demonstrated in the live implementation) complicate a synchronous MUST. Input requested on the right normative level and on whether a time-bound async commitment satisfies MUST semantics. + +**Q2: Formal L2 composition section (for @TMerlini)** + +The triple-hash scheme (`raw_input_hash` / `sanitization_pipeline_hash` / `input_hash`) and the IDENTITY_SENTINEL are the most concretely specified and independently verified pieces of this stack. A formal composition section describing how L2 output feeds into `IProofVerifier.verify()` would strengthen both ERCs. Invitation to co-author or contribute this section, with `gateway.ensub.org` as the normative reference implementation. + +**Q3: proofHash / inputHash joint alignment note (for @VincentWu)** + +The semantic equivalence between `IProofVerifier.verify(inputHash)` and `ERC-8263.anchor(proofHash)` should appear as a cross-reference in both specs. An "ERC-8263 compatibility" subsection here and a matching note in ERC-8263 v0.2 would make this explicit for implementors. Invitation to align wording jointly. + +**Q4: backendId namespace** + +Should `backendId` values be informally self-assigned, or is a lightweight off-chain registry (similar to EIP-155 chain IDs or CAIP network identifiers) desirable? Open for discussion. + +## Security Considerations + +**inputHash poisoning** + +`verify()` confirms that an inference ran correctly on a given input. It does not confirm that the input itself was trustworthy. Input trustworthiness is the responsibility of Layer 2 (input trust layer). Consumers SHOULD verify `sanitization_pipeline_hash` before accepting a proof, or require that a trusted L2 implementation committed the input. + +**Opaque proof bytes** + +The `proof` parameter is backend-specific. Consumers MUST NOT assume structural compatibility of proof bytes across different `IProofVerifier` implementations. + +**Verifier mutability** + +`IVerificationMethod.getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. + +**No execution guarantee** + +This interface defines a `view` function. It provides no guarantee that the underlying proof system is live, that the model referred to by `modelHash` is available, or that the proof was generated honestly. These guarantees must come from the specific proof backend implementation and its associated trust model. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 473e70fcea2f5287cdcc7227232a6d40784b55f9 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 16:01:01 +0800 Subject: [PATCH 02/40] fix: add author email for ERC bot auto-merge --- ERCS/erc-draft-ai-inference-verification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-draft-ai-inference-verification.md b/ERCS/erc-draft-ai-inference-verification.md index 4e38e121a85..a1f87d25c02 100644 --- a/ERCS/erc-draft-ai-inference-verification.md +++ b/ERCS/erc-draft-ai-inference-verification.md @@ -2,7 +2,7 @@ eip: XXXX title: Standard Interfaces for AI Inference Proof Verification description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod) -author: JimmyShi22 (@JimmyShi22) +author: JimmyShi22 (@JimmyShi22) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track From 23c51decdff694b920a0855902658dd54d3d8986 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 16:43:06 +0800 Subject: [PATCH 03/40] refactor: restructure verify() around Input/Computation/Output, add sanitizationPipelineHash --- ERCS/erc-draft-ai-inference-verification.md | 230 ++++++++++++-------- 1 file changed, 142 insertions(+), 88 deletions(-) diff --git a/ERCS/erc-draft-ai-inference-verification.md b/ERCS/erc-draft-ai-inference-verification.md index a1f87d25c02..6106b32d0e1 100644 --- a/ERCS/erc-draft-ai-inference-verification.md +++ b/ERCS/erc-draft-ai-inference-verification.md @@ -1,7 +1,7 @@ --- eip: XXXX title: Standard Interfaces for AI Inference Proof Verification -description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod) +description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod), structured around Input, Computation, and Output author: JimmyShi22 (@JimmyShi22) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft @@ -15,64 +15,114 @@ requires: 165 This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: -- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement to expose a uniform `verify()` entry point +- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement - `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use -These interfaces define how verification is called and composed across proof systems, not how it is implemented internally. They sit at the horizontal coordination layer of the AI agent proof stack, above proof-system-specific contracts and below application logic. +A complete on-chain AI inference event is decomposed into three auditable components: + +| Component | What it captures | +|-----------|-----------------| +| **Input** | What data entered the model, and how it was preprocessed | +| **Computation** | Who ran the model, which model was used, and how execution is verified | +| **Output** | What the model produced | + +Each component has a corresponding struct. `IProofVerifier.verify()` accepts all three, making the full inference lifecycle verifiable end-to-end. This standard is designed to compose with: -- **ERC-8004** for on-chain agent identity resolution +- **ERC-8004** for on-chain agent identity (`agentId` in `InferenceComputation`) - **ERC-8263** for on-chain proof commitment (`anchor()`) - **OCP (Observation Commitment Protocol)** for system-independent digest verification ## Motivation -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results (governance systems, DeFi protocols, autonomous agents) currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. -Existing work addresses adjacent layers: +Existing work addresses adjacent layers but leaves a gap at the interface level: - **ERC-8004** establishes agent identity but does not define verification interfaces -- **ERC-8263** defines a minimal `anchor()` interface for on-chain proof commitment but does not define how that commitment is verified across backends -- **OCP** defines a system-independent verification primitive (`recompute → compare → confirm inclusion`) but does not define backend-facing or consumer-facing interfaces +- **ERC-8263** defines `anchor()` for on-chain proof commitment but not how commitments are verified across backends +- **OCP** defines a system-independent verification primitive but not consumer-facing or backend-facing interfaces -The missing piece is a **common abstract interface** that lets proof backends be treated interchangeably by consumers, without requiring a central registry or coordinator contract. This ERC fills that gap. +Beyond the N×M problem, a flat `verify(modelHash, inputHash, outputHash, proof)` signature obscures an important question: **how was `inputHash` computed?** On-chain AI agents read data from ENS records, NFT metadata, and contract return values before hashing. Without committing to the preprocessing step, a consumer cannot determine whether the input was sanitised, and under what rules. -A central registry was the original framing of this proposal (see discussion thread). The discussion in posts #2–#10 surfaced a cleaner approach: abstract interfaces with no coordinator contract, following the same pattern as ERC-20's `transfer()`. Each consumer holds a direct reference to whichever `IProofVerifier` implementation it chooses, with no hub in between. +This ERC introduces `sanitizationPipelineHash` as a first-class field in `InferenceInput`, directly addressing the interoperability point raised in the discussion thread (see post #8). The three-struct decomposition makes every part of the inference lifecycle independently auditable. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. +### Data Structures + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @notice Captures what data entered the model and how it was preprocessed. +struct InferenceInput { + /// @dev SHA-256 of the raw on-chain source data, before any preprocessing. + /// Set to bytes32(0) if raw input provenance is not tracked. + bytes32 rawInputHash; + + /// @dev SHA-256 of the canonical serialisation of the sanitisation pipeline spec. + /// MUST equal IDENTITY_SENTINEL if no preprocessing was applied: + /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea + bytes32 sanitizationPipelineHash; + + /// @dev SHA-256 of the sanitised input as presented to the model. + /// Equals rawInputHash when sanitizationPipelineHash == IDENTITY_SENTINEL. + /// This value MUST match the proofHash used in ERC-8263 anchor(). + bytes32 inputHash; +} + +/// @notice Captures who ran the model, which model was used, and the execution proof. +struct InferenceComputation { + /// @dev On-chain agent identifier, resolved via ERC-8004 getAgentWallet(). + /// Set to bytes32(0) if agent identity is not required. + bytes32 agentId; + + /// @dev SHA-256 of the model weights or configuration. + bytes32 modelHash; + + /// @dev Backend-specific proof bytes. + /// For zkML: the validity proof. + /// For TEE: the remote attestation report. + /// For opML: the optimistic challenge window reference. + /// For oracle/multisig: the signature bundle. + bytes proof; +} + +/// @notice Captures what the model produced. +struct InferenceOutput { + /// @dev SHA-256 of the model output. + bytes32 outputHash; +} +``` + ### IProofVerifier ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "./InferenceStructs.sol"; + /// @title IProofVerifier /// @notice Interface for AI inference proof verification backends. -/// Implementations MAY support zkML, opML, TEE, oracle, multisig, -/// or any other proof system. interface IProofVerifier { /// @notice Verify an AI inference proof. - /// @param modelHash SHA-256 digest of the model weights or configuration - /// @param inputHash SHA-256 digest of the model input after sanitisation. - /// When no sanitisation pipeline is applied, - /// the corresponding sanitization_pipeline_hash MUST equal - /// the IDENTITY_SENTINEL defined in OCP: - /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea - /// @param outputHash SHA-256 digest of the model output - /// @param proof Backend-specific proof bytes (zkML proof, TEE attestation, etc.) - /// @return True if the proof is valid for the given hashes + /// @param input The input component: raw data hash, preprocessing commitment, sanitised input hash + /// @param computation The computation component: agent identity, model hash, backend proof + /// @param output The output component: model output hash + /// @return True if the proof is valid for the given input/computation/output function verify( - bytes32 modelHash, - bytes32 inputHash, - bytes32 outputHash, - bytes calldata proof + InferenceInput calldata input, + InferenceComputation calldata computation, + InferenceOutput calldata output ) external view returns (bool); /// @notice Human-readable identifier for this proof backend. - /// RECOMMENDED format: "{system}/{version}", e.g. "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1" + /// RECOMMENDED format: "{system}/{version}" + /// Examples: "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1", "oracle-multisig/1" function backendId() external view returns (string memory); } ``` @@ -87,8 +137,6 @@ import "./IProofVerifier.sol"; /// @title IVerificationMethod /// @notice Interface for contracts that declare which proof verifier they use. -/// Consuming ERCs (governance, DeFi, agent systems) implement this to expose -/// their verification method in a discoverable, standardised way. interface IVerificationMethod { /// @notice Returns the proof verifier used by this contract. function getVerifier() external view returns (IProofVerifier); @@ -101,61 +149,59 @@ interface IVerificationMethod { } ``` -### Composition with the AI Agent Proof Stack +### IDENTITY_SENTINEL -This ERC is designed to operate as Layer 5 of the following proof stack. Each layer is independently optional; the full attribution–commitment–verification chain requires all layers acting together. +When no sanitisation pipeline is applied, `InferenceInput.sanitizationPipelineHash` MUST be set to the IDENTITY_SENTINEL constant: ``` -Layer 1 ERC-8004 Agent on-chain identity -Layer 2 Input trust Sanitisation commitments, triple-hash scheme -Layer 3 OCP Portable, system-independent digest verification -Layer 4 ERC-8263 On-chain proof commitment via anchor() -Layer 5 This ERC IProofVerifier / IVerificationMethod abstract interfaces +0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea ``` -**Write path (executed by the agent):** +This is the SHA-256 of the canonical identity pipeline spec, as defined by OCP. Verifiers MUST implement the following branch: + +- `sanitizationPipelineHash == IDENTITY_SENTINEL` → `inputHash == rawInputHash`, skip preprocessing verification +- `sanitizationPipelineHash != IDENTITY_SENTINEL` → `inputHash != rawInputHash`, verify the transformation + +### Composition with the AI Agent Proof Stack ``` -1. input_hash = SHA-256(sanitised_input) // L2 output -2. output_hash = SHA-256(output) -3. ERC-8263.anchor(agentIdScheme, agentId, // L4 write - proofHash) // proofHash == input_hash -4. OCP.record(input_hash) // L3 commitment +Layer 1 ERC-8004 Agent on-chain identity → InferenceComputation.agentId +Layer 2 Input trust Sanitisation commitments → InferenceInput (all three fields) +Layer 3 OCP Portable digest verification → OCP.record(inputHash) +Layer 4 ERC-8263 On-chain commitment → anchor(agentIdScheme, agentId, inputHash) +Layer 5 This ERC IProofVerifier / IVerificationMethod ``` -**Read path (executed by the consumer):** +**Write path:** ``` -1. verifier = consumer.getVerifier() // L5 interface -2. valid = verifier.verify( // L5 interface - modelHash, inputHash, outputHash, proof) -3. Independently verify input_hash via OCP // L3 floor +1. rawInputHash = SHA-256(raw_on_chain_data) +2. sanitizationPipelineHash = SHA-256(pipeline_spec) // or IDENTITY_SENTINEL +3. inputHash = SHA-256(sanitised_input) +4. outputHash = SHA-256(output) +5. ERC-8263.anchor(scheme, agentId, inputHash) // L4 +6. OCP.record(inputHash) // L3 ``` -### Semantic Alignment with ERC-8263 +**Read path:** -The `inputHash` parameter in `IProofVerifier.verify()` is semantically equivalent to the `proofHash` parameter in ERC-8263's `anchor()` function. Both refer to the SHA-256 digest of the sanitised model input (post-L2 processing). - -Implementations that use both interfaces MUST ensure these values are identical for the same inference event. +``` +1. verifier = consumer.getVerifier() +2. valid = verifier.verify(input, computation, output) +3. Independently verify inputHash via OCP // L3 floor +``` -### inputHash Requirements +### Semantic Alignment with ERC-8263 -- `inputHash` MUST be the SHA-256 digest of the input as it was presented to the model after any sanitisation processing. -- When no sanitisation pipeline was applied, implementations MUST set `sanitization_pipeline_hash` to the IDENTITY_SENTINEL defined by OCP: - ``` - 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea - ``` - In this case, `inputHash` equals `raw_input_hash`. +`InferenceInput.inputHash` MUST equal the `proofHash` used in the corresponding `ERC-8263.anchor()` call for the same inference event. Both refer to the SHA-256 of the sanitised model input. ### OCP Anchoring -Implementations of `IProofVerifier` SHOULD call `OCP.record(inputHash)` internally before returning from `verify()`, or commit `inputHash` to an OCP-compatible ledger asynchronously after the call. This ensures that the input commitment survives the proof system going offline and remains independently verifiable by any party. - -Whether this anchoring is synchronous or asynchronous, and on which chain, is implementation-defined. Cross-chain OCP compatibility (EVM and Solana) has been verified in practice (May 2026); the proof envelope schema requires no structural changes across chains. +Implementations of `IProofVerifier` SHOULD anchor `input.inputHash` via OCP before or after `verify()` returns. This ensures the input commitment survives the proof system going offline and remains independently verifiable. Anchoring MAY be asynchronous and is not required to be synchronous with the `verify()` call. ### ERC-165 Support -Implementations SHOULD implement ERC-165 `supportsInterface()`: +Implementations SHOULD support ERC-165: ```solidity function supportsInterface(bytes4 interfaceId) @@ -168,21 +214,27 @@ function supportsInterface(bytes4 interfaceId) ## Rationale -### Abstract interfaces over a central registry +### Three-struct decomposition -A central coordinator contract introduces an unnecessary trust assumption: consumers must trust the registry itself has not been compromised. Abstract interfaces leave the choice of verifier to each consumer. Any contract can hold a reference to any `IProofVerifier` implementation directly — no hub required. This is consistent with OCP's design principle of minimising trust dependencies. +A single flat function signature `verify(modelHash, inputHash, outputHash, proof)` conflates three distinct concerns: -### Why `backendId()` +1. **Input** — What data was used and how was it prepared? `rawInputHash` and `sanitizationPipelineHash` make preprocessing auditable. Without them, a consumer cannot distinguish "clean input, no preprocessing" from "missing provenance." +2. **Computation** — Who ran it and how was it verified? `agentId` links to on-chain identity (ERC-8004); `modelHash` pins the model; `proof` carries the backend-specific execution certificate. +3. **Output** — What was produced? `outputHash` is the only output field; richer output semantics belong in application-layer ERCs. -`backendId()` provides a human-readable identifier for off-chain tooling and on-chain event logs, allowing consumers to display "verified by zkML / TEE / opML" without parsing contract addresses. The `{system}/{version}` convention is recommended but not enforced; a formal registry of backend identifiers is left for a future ERC. +Separating these into structs makes each component independently extensible. An application that does not require agent identity tracking can pass `agentId = bytes32(0)` without changing the interface. -### Why `proof` is opaque bytes +### Why `sanitizationPipelineHash` is not optional + +Making `sanitizationPipelineHash` a required field with a defined sentinel value (rather than an optional parameter) avoids ambiguity. A missing field can mean "no preprocessing" or "preprocessing not tracked." The IDENTITY_SENTINEL makes intent explicit and enables verifiers to implement a single deterministic branch. + +### Abstract interfaces over a central registry -Proof formats are intentionally backend-specific and evolve independently of this interface. Encoding format requirements belong in backend-specific ERCs or companion specifications, not in this interface layer. +A central coordinator contract introduces an unnecessary trust assumption. Abstract interfaces leave the choice of verifier to each consumer, consistent with OCP's principle of minimising trust dependencies. -### Relationship to `IVerificationMethod` +### Why `proof` is opaque bytes -`IVerificationMethod` is a discovery interface. It allows indexers, wallets, and other contracts to determine which verifier a given contract uses without reading bytecode. The `VerifierUpdated` event provides an audit trail for verifier changes, which is security-relevant for consumers that hold significant value. +Proof formats are backend-specific and evolve independently. Encoding requirements belong in backend-specific ERCs, not in this interface layer. ## Backwards Compatibility @@ -190,51 +242,53 @@ No backwards compatibility issues. This ERC introduces new interfaces and does n ## Reference Implementation -> To be contributed. Reference implementations for the following backends are anticipated: -> - zkML backend (RISC Zero / Bonsai) -> - opML optimistic backend -> - TEE backend (AWS Nitro / Intel TDX) -> - Oracle / multisig backend +> To be contributed. Anticipated backend implementations: +> - zkML (RISC Zero / Bonsai) +> - opML optimistic +> - TEE (AWS Nitro / Intel TDX) +> - Oracle / multisig -Live reference implementation of the full L1–L4 stack is available at `gateway.ensub.org` (ERC-8004 + input trust layer, by TMerlini / dinamic.eth). L5 integration is pending. +Live L1–L4 reference: `gateway.ensub.org` (TMerlini / dinamic.eth). L5 integration pending. ## Open Questions -The following questions are open for contributor input before this ERC is finalised. Contributors are welcome to open a PR against this draft or reply in the discussion thread. - **Q1: Should OCP anchoring be SHOULD or MUST? (for @Damonzwicker)** -The current draft uses SHOULD for `OCP.record(inputHash)`. Arguments for MUST: without it, the L3 portability guarantee is absent and the full stack is broken. Arguments against: async anchoring patterns (as demonstrated in the live implementation) complicate a synchronous MUST. Input requested on the right normative level and on whether a time-bound async commitment satisfies MUST semantics. +Current draft: SHOULD. Argument for MUST: without L3 anchoring the portability guarantee is absent. Argument against: async anchoring (as in the live implementation) complicates a synchronous MUST. What is the right normative level? **Q2: Formal L2 composition section (for @TMerlini)** -The triple-hash scheme (`raw_input_hash` / `sanitization_pipeline_hash` / `input_hash`) and the IDENTITY_SENTINEL are the most concretely specified and independently verified pieces of this stack. A formal composition section describing how L2 output feeds into `IProofVerifier.verify()` would strengthen both ERCs. Invitation to co-author or contribute this section, with `gateway.ensub.org` as the normative reference implementation. +The triple-hash scheme and IDENTITY_SENTINEL are the most concretely verified pieces of this stack. A formal section describing how L2 output maps to `InferenceInput` fields would strengthen both ERCs. Invitation to co-author, with `gateway.ensub.org` as the reference implementation. + +**Q3: proofHash / inputHash alignment note (for @VincentWu)** + +`InferenceInput.inputHash` and `ERC-8263.anchor(proofHash)` refer to the same value. This should be a cross-reference in both specs. Invitation to align wording for ERC-8263 v0.2. -**Q3: proofHash / inputHash joint alignment note (for @VincentWu)** +**Q4: rawInputHash optionality** -The semantic equivalence between `IProofVerifier.verify(inputHash)` and `ERC-8263.anchor(proofHash)` should appear as a cross-reference in both specs. An "ERC-8263 compatibility" subsection here and a matching note in ERC-8263 v0.2 would make this explicit for implementors. Invitation to align wording jointly. +`rawInputHash = bytes32(0)` signals "not tracked." Should there be a stronger requirement — e.g., SHOULD be provided when the agent reads on-chain data sources? -**Q4: backendId namespace** +**Q5: backendId namespace** -Should `backendId` values be informally self-assigned, or is a lightweight off-chain registry (similar to EIP-155 chain IDs or CAIP network identifiers) desirable? Open for discussion. +Informally self-assigned vs. a lightweight off-chain registry (like EIP-155 chain IDs)? Open for discussion. ## Security Considerations -**inputHash poisoning** +**Input provenance** -`verify()` confirms that an inference ran correctly on a given input. It does not confirm that the input itself was trustworthy. Input trustworthiness is the responsibility of Layer 2 (input trust layer). Consumers SHOULD verify `sanitization_pipeline_hash` before accepting a proof, or require that a trusted L2 implementation committed the input. +`verify()` confirms a proof is valid for a given input. It does not confirm the input was trustworthy. Consumers SHOULD check `sanitizationPipelineHash` or require a trusted L2 implementation. **Opaque proof bytes** -The `proof` parameter is backend-specific. Consumers MUST NOT assume structural compatibility of proof bytes across different `IProofVerifier` implementations. +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. **Verifier mutability** -`IVerificationMethod.getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events. **No execution guarantee** -This interface defines a `view` function. It provides no guarantee that the underlying proof system is live, that the model referred to by `modelHash` is available, or that the proof was generated honestly. These guarantees must come from the specific proof backend implementation and its associated trust model. +`verify()` is a `view` function. It provides no liveness guarantee for the underlying proof system. ## Copyright From c8f87c4e2d0e8da8fe6ce810e820cbb26a17cac4 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 16:46:52 +0800 Subject: [PATCH 04/40] rename erc-draft to erc-1771, update eip number --- ERCS/erc-1771.md | 295 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 ERCS/erc-1771.md diff --git a/ERCS/erc-1771.md b/ERCS/erc-1771.md new file mode 100644 index 00000000000..cf84cf00613 --- /dev/null +++ b/ERCS/erc-1771.md @@ -0,0 +1,295 @@ +--- +eip: 1771 +title: Standard Interfaces for AI Inference Proof Verification +description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod), structured around Input, Computation, and Output +author: JimmyShi22 (@JimmyShi22) +discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 +status: Draft +type: Standards Track +category: ERC +created: 2026-05-26 +requires: 165 +--- + +## Abstract + +This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: + +- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement +- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use + +A complete on-chain AI inference event is decomposed into three auditable components: + +| Component | What it captures | +|-----------|-----------------| +| **Input** | What data entered the model, and how it was preprocessed | +| **Computation** | Who ran the model, which model was used, and how execution is verified | +| **Output** | What the model produced | + +Each component has a corresponding struct. `IProofVerifier.verify()` accepts all three, making the full inference lifecycle verifiable end-to-end. + +This standard is designed to compose with: +- **ERC-8004** for on-chain agent identity (`agentId` in `InferenceComputation`) +- **ERC-8263** for on-chain proof commitment (`anchor()`) +- **OCP (Observation Commitment Protocol)** for system-independent digest verification + +## Motivation + +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. + +Existing work addresses adjacent layers but leaves a gap at the interface level: + +- **ERC-8004** establishes agent identity but does not define verification interfaces +- **ERC-8263** defines `anchor()` for on-chain proof commitment but not how commitments are verified across backends +- **OCP** defines a system-independent verification primitive but not consumer-facing or backend-facing interfaces + +Beyond the N×M problem, a flat `verify(modelHash, inputHash, outputHash, proof)` signature obscures an important question: **how was `inputHash` computed?** On-chain AI agents read data from ENS records, NFT metadata, and contract return values before hashing. Without committing to the preprocessing step, a consumer cannot determine whether the input was sanitised, and under what rules. + +This ERC introduces `sanitizationPipelineHash` as a first-class field in `InferenceInput`, directly addressing the interoperability point raised in the discussion thread (see post #8). The three-struct decomposition makes every part of the inference lifecycle independently auditable. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### Data Structures + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @notice Captures what data entered the model and how it was preprocessed. +struct InferenceInput { + /// @dev SHA-256 of the raw on-chain source data, before any preprocessing. + /// Set to bytes32(0) if raw input provenance is not tracked. + bytes32 rawInputHash; + + /// @dev SHA-256 of the canonical serialisation of the sanitisation pipeline spec. + /// MUST equal IDENTITY_SENTINEL if no preprocessing was applied: + /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea + bytes32 sanitizationPipelineHash; + + /// @dev SHA-256 of the sanitised input as presented to the model. + /// Equals rawInputHash when sanitizationPipelineHash == IDENTITY_SENTINEL. + /// This value MUST match the proofHash used in ERC-8263 anchor(). + bytes32 inputHash; +} + +/// @notice Captures who ran the model, which model was used, and the execution proof. +struct InferenceComputation { + /// @dev On-chain agent identifier, resolved via ERC-8004 getAgentWallet(). + /// Set to bytes32(0) if agent identity is not required. + bytes32 agentId; + + /// @dev SHA-256 of the model weights or configuration. + bytes32 modelHash; + + /// @dev Backend-specific proof bytes. + /// For zkML: the validity proof. + /// For TEE: the remote attestation report. + /// For opML: the optimistic challenge window reference. + /// For oracle/multisig: the signature bundle. + bytes proof; +} + +/// @notice Captures what the model produced. +struct InferenceOutput { + /// @dev SHA-256 of the model output. + bytes32 outputHash; +} +``` + +### IProofVerifier + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./InferenceStructs.sol"; + +/// @title IProofVerifier +/// @notice Interface for AI inference proof verification backends. +interface IProofVerifier { + /// @notice Verify an AI inference proof. + /// @param input The input component: raw data hash, preprocessing commitment, sanitised input hash + /// @param computation The computation component: agent identity, model hash, backend proof + /// @param output The output component: model output hash + /// @return True if the proof is valid for the given input/computation/output + function verify( + InferenceInput calldata input, + InferenceComputation calldata computation, + InferenceOutput calldata output + ) external view returns (bool); + + /// @notice Human-readable identifier for this proof backend. + /// RECOMMENDED format: "{system}/{version}" + /// Examples: "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1", "oracle-multisig/1" + function backendId() external view returns (string memory); +} +``` + +### IVerificationMethod + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title IVerificationMethod +/// @notice Interface for contracts that declare which proof verifier they use. +interface IVerificationMethod { + /// @notice Returns the proof verifier used by this contract. + function getVerifier() external view returns (IProofVerifier); + + /// @notice MUST be emitted when the verifier address changes. + event VerifierUpdated( + address indexed previousVerifier, + address indexed newVerifier + ); +} +``` + +### IDENTITY_SENTINEL + +When no sanitisation pipeline is applied, `InferenceInput.sanitizationPipelineHash` MUST be set to the IDENTITY_SENTINEL constant: + +``` +0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea +``` + +This is the SHA-256 of the canonical identity pipeline spec, as defined by OCP. Verifiers MUST implement the following branch: + +- `sanitizationPipelineHash == IDENTITY_SENTINEL` → `inputHash == rawInputHash`, skip preprocessing verification +- `sanitizationPipelineHash != IDENTITY_SENTINEL` → `inputHash != rawInputHash`, verify the transformation + +### Composition with the AI Agent Proof Stack + +``` +Layer 1 ERC-8004 Agent on-chain identity → InferenceComputation.agentId +Layer 2 Input trust Sanitisation commitments → InferenceInput (all three fields) +Layer 3 OCP Portable digest verification → OCP.record(inputHash) +Layer 4 ERC-8263 On-chain commitment → anchor(agentIdScheme, agentId, inputHash) +Layer 5 This ERC IProofVerifier / IVerificationMethod +``` + +**Write path:** + +``` +1. rawInputHash = SHA-256(raw_on_chain_data) +2. sanitizationPipelineHash = SHA-256(pipeline_spec) // or IDENTITY_SENTINEL +3. inputHash = SHA-256(sanitised_input) +4. outputHash = SHA-256(output) +5. ERC-8263.anchor(scheme, agentId, inputHash) // L4 +6. OCP.record(inputHash) // L3 +``` + +**Read path:** + +``` +1. verifier = consumer.getVerifier() +2. valid = verifier.verify(input, computation, output) +3. Independently verify inputHash via OCP // L3 floor +``` + +### Semantic Alignment with ERC-8263 + +`InferenceInput.inputHash` MUST equal the `proofHash` used in the corresponding `ERC-8263.anchor()` call for the same inference event. Both refer to the SHA-256 of the sanitised model input. + +### OCP Anchoring + +Implementations of `IProofVerifier` SHOULD anchor `input.inputHash` via OCP before or after `verify()` returns. This ensures the input commitment survives the proof system going offline and remains independently verifiable. Anchoring MAY be asynchronous and is not required to be synchronous with the `verify()` call. + +### ERC-165 Support + +Implementations SHOULD support ERC-165: + +```solidity +function supportsInterface(bytes4 interfaceId) + external view returns (bool) +{ + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} +``` + +## Rationale + +### Three-struct decomposition + +A single flat function signature `verify(modelHash, inputHash, outputHash, proof)` conflates three distinct concerns: + +1. **Input** — What data was used and how was it prepared? `rawInputHash` and `sanitizationPipelineHash` make preprocessing auditable. Without them, a consumer cannot distinguish "clean input, no preprocessing" from "missing provenance." +2. **Computation** — Who ran it and how was it verified? `agentId` links to on-chain identity (ERC-8004); `modelHash` pins the model; `proof` carries the backend-specific execution certificate. +3. **Output** — What was produced? `outputHash` is the only output field; richer output semantics belong in application-layer ERCs. + +Separating these into structs makes each component independently extensible. An application that does not require agent identity tracking can pass `agentId = bytes32(0)` without changing the interface. + +### Why `sanitizationPipelineHash` is not optional + +Making `sanitizationPipelineHash` a required field with a defined sentinel value (rather than an optional parameter) avoids ambiguity. A missing field can mean "no preprocessing" or "preprocessing not tracked." The IDENTITY_SENTINEL makes intent explicit and enables verifiers to implement a single deterministic branch. + +### Abstract interfaces over a central registry + +A central coordinator contract introduces an unnecessary trust assumption. Abstract interfaces leave the choice of verifier to each consumer, consistent with OCP's principle of minimising trust dependencies. + +### Why `proof` is opaque bytes + +Proof formats are backend-specific and evolve independently. Encoding requirements belong in backend-specific ERCs, not in this interface layer. + +## Backwards Compatibility + +No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. + +## Reference Implementation + +> To be contributed. Anticipated backend implementations: +> - zkML (RISC Zero / Bonsai) +> - opML optimistic +> - TEE (AWS Nitro / Intel TDX) +> - Oracle / multisig + +Live L1–L4 reference: `gateway.ensub.org` (TMerlini / dinamic.eth). L5 integration pending. + +## Open Questions + +**Q1: Should OCP anchoring be SHOULD or MUST? (for @Damonzwicker)** + +Current draft: SHOULD. Argument for MUST: without L3 anchoring the portability guarantee is absent. Argument against: async anchoring (as in the live implementation) complicates a synchronous MUST. What is the right normative level? + +**Q2: Formal L2 composition section (for @TMerlini)** + +The triple-hash scheme and IDENTITY_SENTINEL are the most concretely verified pieces of this stack. A formal section describing how L2 output maps to `InferenceInput` fields would strengthen both ERCs. Invitation to co-author, with `gateway.ensub.org` as the reference implementation. + +**Q3: proofHash / inputHash alignment note (for @VincentWu)** + +`InferenceInput.inputHash` and `ERC-8263.anchor(proofHash)` refer to the same value. This should be a cross-reference in both specs. Invitation to align wording for ERC-8263 v0.2. + +**Q4: rawInputHash optionality** + +`rawInputHash = bytes32(0)` signals "not tracked." Should there be a stronger requirement — e.g., SHOULD be provided when the agent reads on-chain data sources? + +**Q5: backendId namespace** + +Informally self-assigned vs. a lightweight off-chain registry (like EIP-155 chain IDs)? Open for discussion. + +## Security Considerations + +**Input provenance** + +`verify()` confirms a proof is valid for a given input. It does not confirm the input was trustworthy. Consumers SHOULD check `sanitizationPipelineHash` or require a trusted L2 implementation. + +**Opaque proof bytes** + +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. + +**Verifier mutability** + +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events. + +**No execution guarantee** + +`verify()` is a `view` function. It provides no liveness guarantee for the underlying proof system. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 37002027f7c82932b9610425ae72532ccdb00474 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 16:47:01 +0800 Subject: [PATCH 05/40] remove old draft filename after rename to erc-1771.md --- ERCS/erc-draft-ai-inference-verification.md | 295 -------------------- 1 file changed, 295 deletions(-) delete mode 100644 ERCS/erc-draft-ai-inference-verification.md diff --git a/ERCS/erc-draft-ai-inference-verification.md b/ERCS/erc-draft-ai-inference-verification.md deleted file mode 100644 index 6106b32d0e1..00000000000 --- a/ERCS/erc-draft-ai-inference-verification.md +++ /dev/null @@ -1,295 +0,0 @@ ---- -eip: XXXX -title: Standard Interfaces for AI Inference Proof Verification -description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod), structured around Input, Computation, and Output -author: JimmyShi22 (@JimmyShi22) -discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 -status: Draft -type: Standards Track -category: ERC -created: 2026-05-26 -requires: 165 ---- - -## Abstract - -This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: - -- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement -- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use - -A complete on-chain AI inference event is decomposed into three auditable components: - -| Component | What it captures | -|-----------|-----------------| -| **Input** | What data entered the model, and how it was preprocessed | -| **Computation** | Who ran the model, which model was used, and how execution is verified | -| **Output** | What the model produced | - -Each component has a corresponding struct. `IProofVerifier.verify()` accepts all three, making the full inference lifecycle verifiable end-to-end. - -This standard is designed to compose with: -- **ERC-8004** for on-chain agent identity (`agentId` in `InferenceComputation`) -- **ERC-8263** for on-chain proof commitment (`anchor()`) -- **OCP (Observation Commitment Protocol)** for system-independent digest verification - -## Motivation - -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. - -Existing work addresses adjacent layers but leaves a gap at the interface level: - -- **ERC-8004** establishes agent identity but does not define verification interfaces -- **ERC-8263** defines `anchor()` for on-chain proof commitment but not how commitments are verified across backends -- **OCP** defines a system-independent verification primitive but not consumer-facing or backend-facing interfaces - -Beyond the N×M problem, a flat `verify(modelHash, inputHash, outputHash, proof)` signature obscures an important question: **how was `inputHash` computed?** On-chain AI agents read data from ENS records, NFT metadata, and contract return values before hashing. Without committing to the preprocessing step, a consumer cannot determine whether the input was sanitised, and under what rules. - -This ERC introduces `sanitizationPipelineHash` as a first-class field in `InferenceInput`, directly addressing the interoperability point raised in the discussion thread (see post #8). The three-struct decomposition makes every part of the inference lifecycle independently auditable. - -## Specification - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. - -### Data Structures - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @notice Captures what data entered the model and how it was preprocessed. -struct InferenceInput { - /// @dev SHA-256 of the raw on-chain source data, before any preprocessing. - /// Set to bytes32(0) if raw input provenance is not tracked. - bytes32 rawInputHash; - - /// @dev SHA-256 of the canonical serialisation of the sanitisation pipeline spec. - /// MUST equal IDENTITY_SENTINEL if no preprocessing was applied: - /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea - bytes32 sanitizationPipelineHash; - - /// @dev SHA-256 of the sanitised input as presented to the model. - /// Equals rawInputHash when sanitizationPipelineHash == IDENTITY_SENTINEL. - /// This value MUST match the proofHash used in ERC-8263 anchor(). - bytes32 inputHash; -} - -/// @notice Captures who ran the model, which model was used, and the execution proof. -struct InferenceComputation { - /// @dev On-chain agent identifier, resolved via ERC-8004 getAgentWallet(). - /// Set to bytes32(0) if agent identity is not required. - bytes32 agentId; - - /// @dev SHA-256 of the model weights or configuration. - bytes32 modelHash; - - /// @dev Backend-specific proof bytes. - /// For zkML: the validity proof. - /// For TEE: the remote attestation report. - /// For opML: the optimistic challenge window reference. - /// For oracle/multisig: the signature bundle. - bytes proof; -} - -/// @notice Captures what the model produced. -struct InferenceOutput { - /// @dev SHA-256 of the model output. - bytes32 outputHash; -} -``` - -### IProofVerifier - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./InferenceStructs.sol"; - -/// @title IProofVerifier -/// @notice Interface for AI inference proof verification backends. -interface IProofVerifier { - /// @notice Verify an AI inference proof. - /// @param input The input component: raw data hash, preprocessing commitment, sanitised input hash - /// @param computation The computation component: agent identity, model hash, backend proof - /// @param output The output component: model output hash - /// @return True if the proof is valid for the given input/computation/output - function verify( - InferenceInput calldata input, - InferenceComputation calldata computation, - InferenceOutput calldata output - ) external view returns (bool); - - /// @notice Human-readable identifier for this proof backend. - /// RECOMMENDED format: "{system}/{version}" - /// Examples: "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1", "oracle-multisig/1" - function backendId() external view returns (string memory); -} -``` - -### IVerificationMethod - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./IProofVerifier.sol"; - -/// @title IVerificationMethod -/// @notice Interface for contracts that declare which proof verifier they use. -interface IVerificationMethod { - /// @notice Returns the proof verifier used by this contract. - function getVerifier() external view returns (IProofVerifier); - - /// @notice MUST be emitted when the verifier address changes. - event VerifierUpdated( - address indexed previousVerifier, - address indexed newVerifier - ); -} -``` - -### IDENTITY_SENTINEL - -When no sanitisation pipeline is applied, `InferenceInput.sanitizationPipelineHash` MUST be set to the IDENTITY_SENTINEL constant: - -``` -0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea -``` - -This is the SHA-256 of the canonical identity pipeline spec, as defined by OCP. Verifiers MUST implement the following branch: - -- `sanitizationPipelineHash == IDENTITY_SENTINEL` → `inputHash == rawInputHash`, skip preprocessing verification -- `sanitizationPipelineHash != IDENTITY_SENTINEL` → `inputHash != rawInputHash`, verify the transformation - -### Composition with the AI Agent Proof Stack - -``` -Layer 1 ERC-8004 Agent on-chain identity → InferenceComputation.agentId -Layer 2 Input trust Sanitisation commitments → InferenceInput (all three fields) -Layer 3 OCP Portable digest verification → OCP.record(inputHash) -Layer 4 ERC-8263 On-chain commitment → anchor(agentIdScheme, agentId, inputHash) -Layer 5 This ERC IProofVerifier / IVerificationMethod -``` - -**Write path:** - -``` -1. rawInputHash = SHA-256(raw_on_chain_data) -2. sanitizationPipelineHash = SHA-256(pipeline_spec) // or IDENTITY_SENTINEL -3. inputHash = SHA-256(sanitised_input) -4. outputHash = SHA-256(output) -5. ERC-8263.anchor(scheme, agentId, inputHash) // L4 -6. OCP.record(inputHash) // L3 -``` - -**Read path:** - -``` -1. verifier = consumer.getVerifier() -2. valid = verifier.verify(input, computation, output) -3. Independently verify inputHash via OCP // L3 floor -``` - -### Semantic Alignment with ERC-8263 - -`InferenceInput.inputHash` MUST equal the `proofHash` used in the corresponding `ERC-8263.anchor()` call for the same inference event. Both refer to the SHA-256 of the sanitised model input. - -### OCP Anchoring - -Implementations of `IProofVerifier` SHOULD anchor `input.inputHash` via OCP before or after `verify()` returns. This ensures the input commitment survives the proof system going offline and remains independently verifiable. Anchoring MAY be asynchronous and is not required to be synchronous with the `verify()` call. - -### ERC-165 Support - -Implementations SHOULD support ERC-165: - -```solidity -function supportsInterface(bytes4 interfaceId) - external view returns (bool) -{ - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; -} -``` - -## Rationale - -### Three-struct decomposition - -A single flat function signature `verify(modelHash, inputHash, outputHash, proof)` conflates three distinct concerns: - -1. **Input** — What data was used and how was it prepared? `rawInputHash` and `sanitizationPipelineHash` make preprocessing auditable. Without them, a consumer cannot distinguish "clean input, no preprocessing" from "missing provenance." -2. **Computation** — Who ran it and how was it verified? `agentId` links to on-chain identity (ERC-8004); `modelHash` pins the model; `proof` carries the backend-specific execution certificate. -3. **Output** — What was produced? `outputHash` is the only output field; richer output semantics belong in application-layer ERCs. - -Separating these into structs makes each component independently extensible. An application that does not require agent identity tracking can pass `agentId = bytes32(0)` without changing the interface. - -### Why `sanitizationPipelineHash` is not optional - -Making `sanitizationPipelineHash` a required field with a defined sentinel value (rather than an optional parameter) avoids ambiguity. A missing field can mean "no preprocessing" or "preprocessing not tracked." The IDENTITY_SENTINEL makes intent explicit and enables verifiers to implement a single deterministic branch. - -### Abstract interfaces over a central registry - -A central coordinator contract introduces an unnecessary trust assumption. Abstract interfaces leave the choice of verifier to each consumer, consistent with OCP's principle of minimising trust dependencies. - -### Why `proof` is opaque bytes - -Proof formats are backend-specific and evolve independently. Encoding requirements belong in backend-specific ERCs, not in this interface layer. - -## Backwards Compatibility - -No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. - -## Reference Implementation - -> To be contributed. Anticipated backend implementations: -> - zkML (RISC Zero / Bonsai) -> - opML optimistic -> - TEE (AWS Nitro / Intel TDX) -> - Oracle / multisig - -Live L1–L4 reference: `gateway.ensub.org` (TMerlini / dinamic.eth). L5 integration pending. - -## Open Questions - -**Q1: Should OCP anchoring be SHOULD or MUST? (for @Damonzwicker)** - -Current draft: SHOULD. Argument for MUST: without L3 anchoring the portability guarantee is absent. Argument against: async anchoring (as in the live implementation) complicates a synchronous MUST. What is the right normative level? - -**Q2: Formal L2 composition section (for @TMerlini)** - -The triple-hash scheme and IDENTITY_SENTINEL are the most concretely verified pieces of this stack. A formal section describing how L2 output maps to `InferenceInput` fields would strengthen both ERCs. Invitation to co-author, with `gateway.ensub.org` as the reference implementation. - -**Q3: proofHash / inputHash alignment note (for @VincentWu)** - -`InferenceInput.inputHash` and `ERC-8263.anchor(proofHash)` refer to the same value. This should be a cross-reference in both specs. Invitation to align wording for ERC-8263 v0.2. - -**Q4: rawInputHash optionality** - -`rawInputHash = bytes32(0)` signals "not tracked." Should there be a stronger requirement — e.g., SHOULD be provided when the agent reads on-chain data sources? - -**Q5: backendId namespace** - -Informally self-assigned vs. a lightweight off-chain registry (like EIP-155 chain IDs)? Open for discussion. - -## Security Considerations - -**Input provenance** - -`verify()` confirms a proof is valid for a given input. It does not confirm the input was trustworthy. Consumers SHOULD check `sanitizationPipelineHash` or require a trusted L2 implementation. - -**Opaque proof bytes** - -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. - -**Verifier mutability** - -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events. - -**No execution guarantee** - -`verify()` is a `view` function. It provides no liveness guarantee for the underlying proof system. - -## Copyright - -Copyright and related rights waived via [CC0](../LICENSE.md). From f087dab941c87df44c2a28e996326a7f55f1da2c Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 17:38:46 +0800 Subject: [PATCH 06/40] refine erc-1771: simplify interface, fix CI errors, add OCP/ERC-8263/input-trust rationale --- ERCS/erc-1771.md | 240 ++++++++++++----------------------------------- 1 file changed, 60 insertions(+), 180 deletions(-) diff --git a/ERCS/erc-1771.md b/ERCS/erc-1771.md index cf84cf00613..cf4400734a6 100644 --- a/ERCS/erc-1771.md +++ b/ERCS/erc-1771.md @@ -1,7 +1,7 @@ --- eip: 1771 -title: Standard Interfaces for AI Inference Proof Verification -description: Minimal abstract interfaces for AI inference proof backends (IProofVerifier) and consuming contracts (IVerificationMethod), structured around Input, Computation, and Output +title: AI Inference Proof Verification Interfaces +description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends author: JimmyShi22 (@JimmyShi22) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft @@ -15,88 +15,48 @@ requires: 165 This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: -- `IProofVerifier` — the interface that proof backends (zkML, opML, TEE, oracle, multisig, etc.) implement +- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point - `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use -A complete on-chain AI inference event is decomposed into three auditable components: +`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. -| Component | What it captures | -|-----------|-----------------| -| **Input** | What data entered the model, and how it was preprocessed | -| **Computation** | Who ran the model, which model was used, and how execution is verified | -| **Output** | What the model produced | - -Each component has a corresponding struct. `IProofVerifier.verify()` accepts all three, making the full inference lifecycle verifiable end-to-end. - -This standard is designed to compose with: -- **ERC-8004** for on-chain agent identity (`agentId` in `InferenceComputation`) -- **ERC-8263** for on-chain proof commitment (`anchor()`) -- **OCP (Observation Commitment Protocol)** for system-independent digest verification +This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](https://github.com/ethereum/ERCs/pull/1748) for on-chain proof commitment. ## Motivation -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. ERCs that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. -Existing work addresses adjacent layers but leaves a gap at the interface level: +OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: -- **ERC-8004** establishes agent identity but does not define verification interfaces -- **ERC-8263** defines `anchor()` for on-chain proof commitment but not how commitments are verified across backends -- **OCP** defines a system-independent verification primitive but not consumer-facing or backend-facing interfaces +- Consumers cannot swap proof backends without code changes +- Tooling cannot introspect which verification method a contract uses +- The proof stack has no uniform entry point for the read/verify path -Beyond the N×M problem, a flat `verify(modelHash, inputHash, outputHash, proof)` signature obscures an important question: **how was `inputHash` computed?** On-chain AI agents read data from ENS records, NFT metadata, and contract return values before hashing. Without committing to the preprocessing step, a consumer cannot determine whether the input was sanitised, and under what rules. - -This ERC introduces `sanitizationPipelineHash` as a first-class field in `InferenceInput`, directly addressing the interoperability point raised in the discussion thread (see post #8). The three-struct decomposition makes every part of the inference lifecycle independently auditable. +This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and ERC-8263 respectively. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### Data Structures +### OCP Alignment -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +OCP (Observation Commitment Protocol) defines the minimum verification primitive: -/// @notice Captures what data entered the model and how it was preprocessed. -struct InferenceInput { - /// @dev SHA-256 of the raw on-chain source data, before any preprocessing. - /// Set to bytes32(0) if raw input provenance is not tracked. - bytes32 rawInputHash; - - /// @dev SHA-256 of the canonical serialisation of the sanitisation pipeline spec. - /// MUST equal IDENTITY_SENTINEL if no preprocessing was applied: - /// 0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea - bytes32 sanitizationPipelineHash; - - /// @dev SHA-256 of the sanitised input as presented to the model. - /// Equals rawInputHash when sanitizationPipelineHash == IDENTITY_SENTINEL. - /// This value MUST match the proofHash used in ERC-8263 anchor(). - bytes32 inputHash; -} +``` +recompute → compare → confirm inclusion +``` -/// @notice Captures who ran the model, which model was used, and the execution proof. -struct InferenceComputation { - /// @dev On-chain agent identifier, resolved via ERC-8004 getAgentWallet(). - /// Set to bytes32(0) if agent identity is not required. - bytes32 agentId; - - /// @dev SHA-256 of the model weights or configuration. - bytes32 modelHash; - - /// @dev Backend-specific proof bytes. - /// For zkML: the validity proof. - /// For TEE: the remote attestation report. - /// For opML: the optimistic challenge window reference. - /// For oracle/multisig: the signature bundle. - bytes proof; -} +A verifier satisfying OCP: +1. Deterministically recomputes a digest from the claimed observation +2. Compares it against the committed digest +3. Confirms the commitment is present in the on-chain record -/// @notice Captures what the model produced. -struct InferenceOutput { - /// @dev SHA-256 of the model output. - bytes32 outputHash; -} -``` +Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: + +- `"zkml/risc0/1"` +- `"opml/optimistic/1"` +- `"tee/nitro/1"` +- `"oracle/multisig/1"` ### IProofVerifier @@ -104,26 +64,26 @@ struct InferenceOutput { // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./InferenceStructs.sol"; - /// @title IProofVerifier /// @notice Interface for AI inference proof verification backends. +/// Each implementation executes the OCP verification primitive +/// (recompute → compare → confirm inclusion) for a specific proof system. interface IProofVerifier { /// @notice Verify an AI inference proof. - /// @param input The input component: raw data hash, preprocessing commitment, sanitised input hash - /// @param computation The computation component: agent identity, model hash, backend proof - /// @param output The output component: model output hash - /// @return True if the proof is valid for the given input/computation/output + /// @param inputHash SHA-256 digest of the model input + /// @param outputHash SHA-256 digest of the model output + /// @param proof Backend-specific proof bytes + /// @return True if the proof is valid for the given input and output function verify( - InferenceInput calldata input, - InferenceComputation calldata computation, - InferenceOutput calldata output + bytes32 inputHash, + bytes32 outputHash, + bytes calldata proof ) external view returns (bool); - /// @notice Human-readable identifier for this proof backend. - /// RECOMMENDED format: "{system}/{version}" - /// Examples: "risc0-zkml/1", "opml-optimistic/1", "tee-nitro/1", "oracle-multisig/1" - function backendId() external view returns (string memory); + /// @notice OCP proof profile identifier for this backend. + /// RECOMMENDED format: "{system}/{variant}/{version}" + /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" + function proofProfile() external view returns (string memory); } ``` @@ -149,59 +109,9 @@ interface IVerificationMethod { } ``` -### IDENTITY_SENTINEL - -When no sanitisation pipeline is applied, `InferenceInput.sanitizationPipelineHash` MUST be set to the IDENTITY_SENTINEL constant: - -``` -0x8116eec29078e8f57c07077d5e8080a35bde73036581df3abb93755d1b1a16ea -``` - -This is the SHA-256 of the canonical identity pipeline spec, as defined by OCP. Verifiers MUST implement the following branch: - -- `sanitizationPipelineHash == IDENTITY_SENTINEL` → `inputHash == rawInputHash`, skip preprocessing verification -- `sanitizationPipelineHash != IDENTITY_SENTINEL` → `inputHash != rawInputHash`, verify the transformation +### Interface Detection -### Composition with the AI Agent Proof Stack - -``` -Layer 1 ERC-8004 Agent on-chain identity → InferenceComputation.agentId -Layer 2 Input trust Sanitisation commitments → InferenceInput (all three fields) -Layer 3 OCP Portable digest verification → OCP.record(inputHash) -Layer 4 ERC-8263 On-chain commitment → anchor(agentIdScheme, agentId, inputHash) -Layer 5 This ERC IProofVerifier / IVerificationMethod -``` - -**Write path:** - -``` -1. rawInputHash = SHA-256(raw_on_chain_data) -2. sanitizationPipelineHash = SHA-256(pipeline_spec) // or IDENTITY_SENTINEL -3. inputHash = SHA-256(sanitised_input) -4. outputHash = SHA-256(output) -5. ERC-8263.anchor(scheme, agentId, inputHash) // L4 -6. OCP.record(inputHash) // L3 -``` - -**Read path:** - -``` -1. verifier = consumer.getVerifier() -2. valid = verifier.verify(input, computation, output) -3. Independently verify inputHash via OCP // L3 floor -``` - -### Semantic Alignment with ERC-8263 - -`InferenceInput.inputHash` MUST equal the `proofHash` used in the corresponding `ERC-8263.anchor()` call for the same inference event. Both refer to the SHA-256 of the sanitised model input. - -### OCP Anchoring - -Implementations of `IProofVerifier` SHOULD anchor `input.inputHash` via OCP before or after `verify()` returns. This ensures the input commitment survives the proof system going offline and remains independently verifiable. Anchoring MAY be asynchronous and is not required to be synchronous with the `verify()` call. - -### ERC-165 Support - -Implementations SHOULD support ERC-165: +Implementations SHOULD support [ERC-165](./erc-165.md): ```solidity function supportsInterface(bytes4 interfaceId) @@ -214,27 +124,21 @@ function supportsInterface(bytes4 interfaceId) ## Rationale -### Three-struct decomposition - -A single flat function signature `verify(modelHash, inputHash, outputHash, proof)` conflates three distinct concerns: - -1. **Input** — What data was used and how was it prepared? `rawInputHash` and `sanitizationPipelineHash` make preprocessing auditable. Without them, a consumer cannot distinguish "clean input, no preprocessing" from "missing provenance." -2. **Computation** — Who ran it and how was it verified? `agentId` links to on-chain identity (ERC-8004); `modelHash` pins the model; `proof` carries the backend-specific execution certificate. -3. **Output** — What was produced? `outputHash` is the only output field; richer output semantics belong in application-layer ERCs. +### Relationship to ERC-8263 -Separating these into structs makes each component independently extensible. An application that does not require agent identity tracking can pass `agentId = bytes32(0)` without changing the interface. +ERC-8263 defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. -### Why `sanitizationPipelineHash` is not optional +The `inputHash` parameter in `verify()` corresponds to the `proofHash` used in the ERC-8263 `anchor()` call for the same inference event. Both are the SHA-256 digest of the model input as presented to the proof system. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. -Making `sanitizationPipelineHash` a required field with a defined sentinel value (rather than an optional parameter) avoids ambiguity. A missing field can mean "no preprocessing" or "preprocessing not tracked." The IDENTITY_SENTINEL makes intent explicit and enables verifiers to implement a single deterministic branch. +### Relationship to the Input Trust Layer -### Abstract interfaces over a central registry +On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). -A central coordinator contract introduces an unnecessary trust assumption. Abstract interfaces leave the choice of verifier to each consumer, consistent with OCP's principle of minimising trust dependencies. +`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. -### Why `proof` is opaque bytes +### Relationship to OCP -Proof formats are backend-specific and evolve independently. Encoding requirements belong in backend-specific ERCs, not in this interface layer. +OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. ## Backwards Compatibility @@ -242,53 +146,29 @@ No backwards compatibility issues. This ERC introduces new interfaces and does n ## Reference Implementation -> To be contributed. Anticipated backend implementations: -> - zkML (RISC Zero / Bonsai) -> - opML optimistic -> - TEE (AWS Nitro / Intel TDX) -> - Oracle / multisig - -Live L1–L4 reference: `gateway.ensub.org` (TMerlini / dinamic.eth). L5 integration pending. - -## Open Questions - -**Q1: Should OCP anchoring be SHOULD or MUST? (for @Damonzwicker)** - -Current draft: SHOULD. Argument for MUST: without L3 anchoring the portability guarantee is absent. Argument against: async anchoring (as in the live implementation) complicates a synchronous MUST. What is the right normative level? - -**Q2: Formal L2 composition section (for @TMerlini)** - -The triple-hash scheme and IDENTITY_SENTINEL are the most concretely verified pieces of this stack. A formal section describing how L2 output maps to `InferenceInput` fields would strengthen both ERCs. Invitation to co-author, with `gateway.ensub.org` as the reference implementation. - -**Q3: proofHash / inputHash alignment note (for @VincentWu)** - -`InferenceInput.inputHash` and `ERC-8263.anchor(proofHash)` refer to the same value. This should be a cross-reference in both specs. Invitation to align wording for ERC-8263 v0.2. - -**Q4: rawInputHash optionality** - -`rawInputHash = bytes32(0)` signals "not tracked." Should there be a stronger requirement — e.g., SHOULD be provided when the agent reads on-chain data sources? - -**Q5: backendId namespace** - -Informally self-assigned vs. a lightweight off-chain registry (like EIP-155 chain IDs)? Open for discussion. +> To be contributed. Anticipated implementations: +> - zkML backend (RISC Zero / Bonsai) +> - opML optimistic backend +> - TEE backend (AWS Nitro / Intel TDX) +> - Oracle / multisig backend ## Security Considerations -**Input provenance** +**Input trustworthiness** -`verify()` confirms a proof is valid for a given input. It does not confirm the input was trustworthy. Consumers SHOULD check `sanitizationPipelineHash` or require a trusted L2 implementation. +`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. **Opaque proof bytes** -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. **Verifier mutability** -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events. +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. -**No execution guarantee** +**No liveness guarantee** -`verify()` is a `view` function. It provides no liveness guarantee for the underlying proof system. +`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. ## Copyright From c563fab41e316c7abb794d6c5d210073d3674ccf Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 17:50:35 +0800 Subject: [PATCH 07/40] add erc-8288: AI inference proof verification interfaces --- ERCS/erc-8288.md | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 ERCS/erc-8288.md diff --git a/ERCS/erc-8288.md b/ERCS/erc-8288.md new file mode 100644 index 00000000000..b95b38c3e09 --- /dev/null +++ b/ERCS/erc-8288.md @@ -0,0 +1,175 @@ +--- +eip: 8288 +title: AI Inference Proof Verification Interfaces +description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends +author: JimmyShi22 (@JimmyShi22) +discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 +status: Draft +type: Standards Track +category: ERC +created: 2026-05-26 +requires: 165 +--- + +## Abstract + +This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: + +- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point +- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use + +`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. + +This standard composes with [ERC-8004](./eip-8004.md) for agent identity. + +## Motivation + +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. + +OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: + +- Consumers cannot swap proof backends without code changes +- Tooling cannot introspect which verification method a contract uses +- The proof stack has no uniform entry point for the read/verify path + +This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and the proof commitment layer respectively. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### OCP Alignment + +OCP (Observation Commitment Protocol) defines the minimum verification primitive: + +``` +recompute → compare → confirm inclusion +``` + +A verifier satisfying OCP: +1. Deterministically recomputes a digest from the claimed observation +2. Compares it against the committed digest +3. Confirms the commitment is present in the on-chain record + +Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: + +- `"zkml/risc0/1"` +- `"opml/optimistic/1"` +- `"tee/nitro/1"` +- `"oracle/multisig/1"` + +### IProofVerifier + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title IProofVerifier +/// @notice Interface for AI inference proof verification backends. +/// Each implementation executes the OCP verification primitive +/// (recompute → compare → confirm inclusion) for a specific proof system. +interface IProofVerifier { + /// @notice Verify an AI inference proof. + /// @param inputHash SHA-256 digest of the model input + /// @param outputHash SHA-256 digest of the model output + /// @param proof Backend-specific proof bytes + /// @return True if the proof is valid for the given input and output + function verify( + bytes32 inputHash, + bytes32 outputHash, + bytes calldata proof + ) external view returns (bool); + + /// @notice OCP proof profile identifier for this backend. + /// RECOMMENDED format: "{system}/{variant}/{version}" + /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" + function proofProfile() external view returns (string memory); +} +``` + +### IVerificationMethod + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title IVerificationMethod +/// @notice Interface for contracts that declare which proof verifier they use. +interface IVerificationMethod { + /// @notice Returns the proof verifier used by this contract. + function getVerifier() external view returns (IProofVerifier); + + /// @notice MUST be emitted when the verifier address changes. + event VerifierUpdated( + address indexed previousVerifier, + address indexed newVerifier + ); +} +``` + +### Interface Detection + +Implementations SHOULD support [ERC-165](./eip-165.md): + +```solidity +function supportsInterface(bytes4 interfaceId) + external view returns (bool) +{ + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} +``` + +## Rationale + +### Relationship to the Proof Commitment Layer + +The proof commitment layer defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. + +`inputHash` is the same SHA-256 digest as the `proofHash` committed on-chain for the same inference event. The two layers are complementary: the commitment layer handles anchoring, this ERC handles verification. + +### Relationship to the Input Trust Layer + +On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). + +`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. + +### Relationship to OCP + +OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. + +## Backwards Compatibility + +No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. + +## Reference Implementation + +> To be contributed. Anticipated implementations: +> - zkML backend (RISC Zero / Bonsai) +> - opML optimistic backend +> - TEE backend (AWS Nitro / Intel TDX) +> - Oracle / multisig backend + +## Security Considerations + +**Input trustworthiness** + +`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. + +**Opaque proof bytes** + +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. + +**Verifier mutability** + +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. + +**No liveness guarantee** + +`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From d13dc21968893c4a389c28faa53591354332df0a Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 26 May 2026 17:50:44 +0800 Subject: [PATCH 08/40] remove erc-1771.md, replaced by erc-8288.md --- ERCS/erc-1771.md | 175 ----------------------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 ERCS/erc-1771.md diff --git a/ERCS/erc-1771.md b/ERCS/erc-1771.md deleted file mode 100644 index cf4400734a6..00000000000 --- a/ERCS/erc-1771.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -eip: 1771 -title: AI Inference Proof Verification Interfaces -description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends -author: JimmyShi22 (@JimmyShi22) -discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 -status: Draft -type: Standards Track -category: ERC -created: 2026-05-26 -requires: 165 ---- - -## Abstract - -This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: - -- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point -- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use - -`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. - -This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](https://github.com/ethereum/ERCs/pull/1748) for on-chain proof commitment. - -## Motivation - -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. - -OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: - -- Consumers cannot swap proof backends without code changes -- Tooling cannot introspect which verification method a contract uses -- The proof stack has no uniform entry point for the read/verify path - -This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and ERC-8263 respectively. - -## Specification - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. - -### OCP Alignment - -OCP (Observation Commitment Protocol) defines the minimum verification primitive: - -``` -recompute → compare → confirm inclusion -``` - -A verifier satisfying OCP: -1. Deterministically recomputes a digest from the claimed observation -2. Compares it against the committed digest -3. Confirms the commitment is present in the on-chain record - -Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: - -- `"zkml/risc0/1"` -- `"opml/optimistic/1"` -- `"tee/nitro/1"` -- `"oracle/multisig/1"` - -### IProofVerifier - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title IProofVerifier -/// @notice Interface for AI inference proof verification backends. -/// Each implementation executes the OCP verification primitive -/// (recompute → compare → confirm inclusion) for a specific proof system. -interface IProofVerifier { - /// @notice Verify an AI inference proof. - /// @param inputHash SHA-256 digest of the model input - /// @param outputHash SHA-256 digest of the model output - /// @param proof Backend-specific proof bytes - /// @return True if the proof is valid for the given input and output - function verify( - bytes32 inputHash, - bytes32 outputHash, - bytes calldata proof - ) external view returns (bool); - - /// @notice OCP proof profile identifier for this backend. - /// RECOMMENDED format: "{system}/{variant}/{version}" - /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" - function proofProfile() external view returns (string memory); -} -``` - -### IVerificationMethod - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./IProofVerifier.sol"; - -/// @title IVerificationMethod -/// @notice Interface for contracts that declare which proof verifier they use. -interface IVerificationMethod { - /// @notice Returns the proof verifier used by this contract. - function getVerifier() external view returns (IProofVerifier); - - /// @notice MUST be emitted when the verifier address changes. - event VerifierUpdated( - address indexed previousVerifier, - address indexed newVerifier - ); -} -``` - -### Interface Detection - -Implementations SHOULD support [ERC-165](./erc-165.md): - -```solidity -function supportsInterface(bytes4 interfaceId) - external view returns (bool) -{ - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; -} -``` - -## Rationale - -### Relationship to ERC-8263 - -ERC-8263 defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. - -The `inputHash` parameter in `verify()` corresponds to the `proofHash` used in the ERC-8263 `anchor()` call for the same inference event. Both are the SHA-256 digest of the model input as presented to the proof system. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. - -### Relationship to the Input Trust Layer - -On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). - -`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. - -### Relationship to OCP - -OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. - -## Backwards Compatibility - -No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. - -## Reference Implementation - -> To be contributed. Anticipated implementations: -> - zkML backend (RISC Zero / Bonsai) -> - opML optimistic backend -> - TEE backend (AWS Nitro / Intel TDX) -> - Oracle / multisig backend - -## Security Considerations - -**Input trustworthiness** - -`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. - -**Opaque proof bytes** - -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. - -**Verifier mutability** - -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. - -**No liveness guarantee** - -`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. - -## Copyright - -Copyright and related rights waived via [CC0](../LICENSE.md). From 9edcd7a653a1546391ecf7f68dfd3a6459fc69aa Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Wed, 27 May 2026 10:07:07 +0800 Subject: [PATCH 09/40] Update ERCS/erc-8288.md Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- ERCS/erc-8288.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8288.md b/ERCS/erc-8288.md index b95b38c3e09..a0f8245b542 100644 --- a/ERCS/erc-8288.md +++ b/ERCS/erc-8288.md @@ -1,5 +1,5 @@ --- -eip: 8288 +eip: 8274 title: AI Inference Proof Verification Interfaces description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends author: JimmyShi22 (@JimmyShi22) From 1958d7f3a5de05040fbb290113bbf463f736964d Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Wed, 27 May 2026 10:07:24 +0800 Subject: [PATCH 10/40] Update ERCS/erc-8288.md Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- ERCS/erc-8288.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8288.md b/ERCS/erc-8288.md index a0f8245b542..b87a9966065 100644 --- a/ERCS/erc-8288.md +++ b/ERCS/erc-8288.md @@ -3,7 +3,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends author: JimmyShi22 (@JimmyShi22) -discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 +discussions-to: https://ethereum-magicians.org/t/erc-8274-ai-inference-proof-verification/28083 status: Draft type: Standards Track category: ERC From 0fabaa01246739008954a09a247ba132b206f390 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Wed, 27 May 2026 10:07:53 +0800 Subject: [PATCH 11/40] Update ERCS/erc-8288.md Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- ERCS/erc-8288.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8288.md b/ERCS/erc-8288.md index b87a9966065..27bd43cedf1 100644 --- a/ERCS/erc-8288.md +++ b/ERCS/erc-8288.md @@ -1,6 +1,6 @@ --- eip: 8274 -title: AI Inference Proof Verification Interfaces +title: AI Inference Proof Verification description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends author: JimmyShi22 (@JimmyShi22) discussions-to: https://ethereum-magicians.org/t/erc-8274-ai-inference-proof-verification/28083 From 714780999943f2938126e06ad27140af6270d8fb Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Wed, 27 May 2026 10:09:52 +0800 Subject: [PATCH 12/40] =?UTF-8?q?rename:=20erc-8288.md=20=E2=86=92=20erc-8?= =?UTF-8?q?274.md=20(official=20ERC=20number=20assigned)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 ERCS/erc-8274.md diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md new file mode 100644 index 00000000000..27bd43cedf1 --- /dev/null +++ b/ERCS/erc-8274.md @@ -0,0 +1,175 @@ +--- +eip: 8274 +title: AI Inference Proof Verification +description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends +author: JimmyShi22 (@JimmyShi22) +discussions-to: https://ethereum-magicians.org/t/erc-8274-ai-inference-proof-verification/28083 +status: Draft +type: Standards Track +category: ERC +created: 2026-05-26 +requires: 165 +--- + +## Abstract + +This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: + +- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point +- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use + +`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. + +This standard composes with [ERC-8004](./eip-8004.md) for agent identity. + +## Motivation + +On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. + +OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: + +- Consumers cannot swap proof backends without code changes +- Tooling cannot introspect which verification method a contract uses +- The proof stack has no uniform entry point for the read/verify path + +This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and the proof commitment layer respectively. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### OCP Alignment + +OCP (Observation Commitment Protocol) defines the minimum verification primitive: + +``` +recompute → compare → confirm inclusion +``` + +A verifier satisfying OCP: +1. Deterministically recomputes a digest from the claimed observation +2. Compares it against the committed digest +3. Confirms the commitment is present in the on-chain record + +Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: + +- `"zkml/risc0/1"` +- `"opml/optimistic/1"` +- `"tee/nitro/1"` +- `"oracle/multisig/1"` + +### IProofVerifier + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title IProofVerifier +/// @notice Interface for AI inference proof verification backends. +/// Each implementation executes the OCP verification primitive +/// (recompute → compare → confirm inclusion) for a specific proof system. +interface IProofVerifier { + /// @notice Verify an AI inference proof. + /// @param inputHash SHA-256 digest of the model input + /// @param outputHash SHA-256 digest of the model output + /// @param proof Backend-specific proof bytes + /// @return True if the proof is valid for the given input and output + function verify( + bytes32 inputHash, + bytes32 outputHash, + bytes calldata proof + ) external view returns (bool); + + /// @notice OCP proof profile identifier for this backend. + /// RECOMMENDED format: "{system}/{variant}/{version}" + /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" + function proofProfile() external view returns (string memory); +} +``` + +### IVerificationMethod + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title IVerificationMethod +/// @notice Interface for contracts that declare which proof verifier they use. +interface IVerificationMethod { + /// @notice Returns the proof verifier used by this contract. + function getVerifier() external view returns (IProofVerifier); + + /// @notice MUST be emitted when the verifier address changes. + event VerifierUpdated( + address indexed previousVerifier, + address indexed newVerifier + ); +} +``` + +### Interface Detection + +Implementations SHOULD support [ERC-165](./eip-165.md): + +```solidity +function supportsInterface(bytes4 interfaceId) + external view returns (bool) +{ + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} +``` + +## Rationale + +### Relationship to the Proof Commitment Layer + +The proof commitment layer defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. + +`inputHash` is the same SHA-256 digest as the `proofHash` committed on-chain for the same inference event. The two layers are complementary: the commitment layer handles anchoring, this ERC handles verification. + +### Relationship to the Input Trust Layer + +On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). + +`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. + +### Relationship to OCP + +OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. + +## Backwards Compatibility + +No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. + +## Reference Implementation + +> To be contributed. Anticipated implementations: +> - zkML backend (RISC Zero / Bonsai) +> - opML optimistic backend +> - TEE backend (AWS Nitro / Intel TDX) +> - Oracle / multisig backend + +## Security Considerations + +**Input trustworthiness** + +`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. + +**Opaque proof bytes** + +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. + +**Verifier mutability** + +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. + +**No liveness guarantee** + +`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 21896f7f0719cd7677c7a1ec33d54efee6e3f568 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Wed, 27 May 2026 10:10:03 +0800 Subject: [PATCH 13/40] remove: erc-8288.md (replaced by erc-8274.md) --- ERCS/erc-8288.md | 175 ----------------------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 ERCS/erc-8288.md diff --git a/ERCS/erc-8288.md b/ERCS/erc-8288.md deleted file mode 100644 index 27bd43cedf1..00000000000 --- a/ERCS/erc-8288.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -eip: 8274 -title: AI Inference Proof Verification -description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends -author: JimmyShi22 (@JimmyShi22) -discussions-to: https://ethereum-magicians.org/t/erc-8274-ai-inference-proof-verification/28083 -status: Draft -type: Standards Track -category: ERC -created: 2026-05-26 -requires: 165 ---- - -## Abstract - -This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: - -- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point -- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use - -`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. - -This standard composes with [ERC-8004](./eip-8004.md) for agent identity. - -## Motivation - -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. - -OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: - -- Consumers cannot swap proof backends without code changes -- Tooling cannot introspect which verification method a contract uses -- The proof stack has no uniform entry point for the read/verify path - -This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and the proof commitment layer respectively. - -## Specification - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. - -### OCP Alignment - -OCP (Observation Commitment Protocol) defines the minimum verification primitive: - -``` -recompute → compare → confirm inclusion -``` - -A verifier satisfying OCP: -1. Deterministically recomputes a digest from the claimed observation -2. Compares it against the committed digest -3. Confirms the commitment is present in the on-chain record - -Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: - -- `"zkml/risc0/1"` -- `"opml/optimistic/1"` -- `"tee/nitro/1"` -- `"oracle/multisig/1"` - -### IProofVerifier - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title IProofVerifier -/// @notice Interface for AI inference proof verification backends. -/// Each implementation executes the OCP verification primitive -/// (recompute → compare → confirm inclusion) for a specific proof system. -interface IProofVerifier { - /// @notice Verify an AI inference proof. - /// @param inputHash SHA-256 digest of the model input - /// @param outputHash SHA-256 digest of the model output - /// @param proof Backend-specific proof bytes - /// @return True if the proof is valid for the given input and output - function verify( - bytes32 inputHash, - bytes32 outputHash, - bytes calldata proof - ) external view returns (bool); - - /// @notice OCP proof profile identifier for this backend. - /// RECOMMENDED format: "{system}/{variant}/{version}" - /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" - function proofProfile() external view returns (string memory); -} -``` - -### IVerificationMethod - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./IProofVerifier.sol"; - -/// @title IVerificationMethod -/// @notice Interface for contracts that declare which proof verifier they use. -interface IVerificationMethod { - /// @notice Returns the proof verifier used by this contract. - function getVerifier() external view returns (IProofVerifier); - - /// @notice MUST be emitted when the verifier address changes. - event VerifierUpdated( - address indexed previousVerifier, - address indexed newVerifier - ); -} -``` - -### Interface Detection - -Implementations SHOULD support [ERC-165](./eip-165.md): - -```solidity -function supportsInterface(bytes4 interfaceId) - external view returns (bool) -{ - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; -} -``` - -## Rationale - -### Relationship to the Proof Commitment Layer - -The proof commitment layer defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. - -`inputHash` is the same SHA-256 digest as the `proofHash` committed on-chain for the same inference event. The two layers are complementary: the commitment layer handles anchoring, this ERC handles verification. - -### Relationship to the Input Trust Layer - -On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). - -`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. - -### Relationship to OCP - -OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. - -## Backwards Compatibility - -No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. - -## Reference Implementation - -> To be contributed. Anticipated implementations: -> - zkML backend (RISC Zero / Bonsai) -> - opML optimistic backend -> - TEE backend (AWS Nitro / Intel TDX) -> - Oracle / multisig backend - -## Security Considerations - -**Input trustworthiness** - -`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. - -**Opaque proof bytes** - -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. - -**Verifier mutability** - -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. - -**No liveness guarantee** - -`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. - -## Copyright - -Copyright and related rights waived via [CC0](../LICENSE.md). From bd032d437b4502a3cb28c488fad9b558f3177622 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Thu, 28 May 2026 16:58:03 +0800 Subject: [PATCH 14/40] update ERC-8274: add metadata param, stateless verifier design, OCP rationale, WYRIWE, proofProfile bytes32 --- ERCS/erc-8274.md | 176 +---------------------------------------------- 1 file changed, 1 insertion(+), 175 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 27bd43cedf1..49eda2779dc 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -1,175 +1 @@ ---- -eip: 8274 -title: AI Inference Proof Verification -description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends -author: JimmyShi22 (@JimmyShi22) -discussions-to: https://ethereum-magicians.org/t/erc-8274-ai-inference-proof-verification/28083 -status: Draft -type: Standards Track -category: ERC -created: 2026-05-26 -requires: 165 ---- - -## Abstract - -This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: - -- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point -- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use - -`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. - -This standard composes with [ERC-8004](./eip-8004.md) for agent identity. - -## Motivation - -On-chain AI inference involves multiple competing proof systems — zkML, opML, TEE enclaves, oracle-based attestation, and multisig — each with distinct interfaces, trust assumptions, and deployment patterns. Contracts that consume AI inference results currently face an N×M integration problem: each consumer must write separate integration code for each proof backend it wishes to support. - -OCP defines the verification primitive that any proof system must satisfy, but does not prescribe a Solidity interface. Without a shared interface: - -- Consumers cannot swap proof backends without code changes -- Tooling cannot introspect which verification method a contract uses -- The proof stack has no uniform entry point for the read/verify path - -This ERC fills the interface gap. It does not define how proofs are constructed, how inputs are sanitised, or how commitments are anchored on-chain — those are the responsibilities of the proof backend, the input trust layer, and the proof commitment layer respectively. - -## Specification - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. - -### OCP Alignment - -OCP (Observation Commitment Protocol) defines the minimum verification primitive: - -``` -recompute → compare → confirm inclusion -``` - -A verifier satisfying OCP: -1. Deterministically recomputes a digest from the claimed observation -2. Compares it against the committed digest -3. Confirms the commitment is present in the on-chain record - -Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. The RECOMMENDED format is `"{system}/{variant}/{version}"`, for example: - -- `"zkml/risc0/1"` -- `"opml/optimistic/1"` -- `"tee/nitro/1"` -- `"oracle/multisig/1"` - -### IProofVerifier - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title IProofVerifier -/// @notice Interface for AI inference proof verification backends. -/// Each implementation executes the OCP verification primitive -/// (recompute → compare → confirm inclusion) for a specific proof system. -interface IProofVerifier { - /// @notice Verify an AI inference proof. - /// @param inputHash SHA-256 digest of the model input - /// @param outputHash SHA-256 digest of the model output - /// @param proof Backend-specific proof bytes - /// @return True if the proof is valid for the given input and output - function verify( - bytes32 inputHash, - bytes32 outputHash, - bytes calldata proof - ) external view returns (bool); - - /// @notice OCP proof profile identifier for this backend. - /// RECOMMENDED format: "{system}/{variant}/{version}" - /// Examples: "zkml/risc0/1", "opml/optimistic/1", "tee/nitro/1" - function proofProfile() external view returns (string memory); -} -``` - -### IVerificationMethod - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "./IProofVerifier.sol"; - -/// @title IVerificationMethod -/// @notice Interface for contracts that declare which proof verifier they use. -interface IVerificationMethod { - /// @notice Returns the proof verifier used by this contract. - function getVerifier() external view returns (IProofVerifier); - - /// @notice MUST be emitted when the verifier address changes. - event VerifierUpdated( - address indexed previousVerifier, - address indexed newVerifier - ); -} -``` - -### Interface Detection - -Implementations SHOULD support [ERC-165](./eip-165.md): - -```solidity -function supportsInterface(bytes4 interfaceId) - external view returns (bool) -{ - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; -} -``` - -## Rationale - -### Relationship to the Proof Commitment Layer - -The proof commitment layer defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, proof)`. - -`inputHash` is the same SHA-256 digest as the `proofHash` committed on-chain for the same inference event. The two layers are complementary: the commitment layer handles anchoring, this ERC handles verification. - -### Relationship to the Input Trust Layer - -On-chain AI agents typically preprocess input data before it is presented to the model — reading from ENS records, NFT metadata, or contract return values and applying sanitisation rules before hashing. This preprocessing pipeline, and the commitment to its specification, is the concern of the input trust layer (see `gateway.ensub.org` for a reference implementation of the full L1–L4 stack). - -`IProofVerifier.verify()` operates on the output of the input trust layer: `inputHash` is the SHA-256 digest of the sanitised input after any preprocessing has been applied. This ERC does not prescribe how `inputHash` was derived. Consumers that require provenance guarantees about the preprocessing step SHOULD verify the input commitment through the input trust layer independently of calling `verify()`. - -### Relationship to OCP - -OCP (Observation Commitment Protocol) defines the minimum verification primitive that any proof system must satisfy: `recompute → compare → confirm inclusion`. This ERC provides the Solidity interface layer for OCP-compatible backends. `proofProfile()` identifies which OCP proof profile an implementation uses, and `verify()` is the on-chain execution of the OCP primitive for that profile. - -## Backwards Compatibility - -No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. - -## Reference Implementation - -> To be contributed. Anticipated implementations: -> - zkML backend (RISC Zero / Bonsai) -> - opML optimistic backend -> - TEE backend (AWS Nitro / Intel TDX) -> - Oracle / multisig backend - -## Security Considerations - -**Input trustworthiness** - -`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input commitment independently before accepting a proof. - -**Opaque proof bytes** - -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. - -**Verifier mutability** - -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. - -**No liveness guarantee** - -`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. - -## Copyright - -Copyright and related rights waived via [CC0](../LICENSE.md). +LS0tCmVpcDogODI3NAp0aXRsZTogQUkgSW5mZXJlbmNlIFByb29mIFZlcmlmaWNhdGlvbiBJbnRlcmZhY2VzCmRlc2NyaXB0aW9uOiBNaW5pbWFsIGFic3RyYWN0IGludGVyZmFjZXMgZm9yIG9uLWNoYWluIEFJIGluZmVyZW5jZSBwcm9vZiB2ZXJpZmljYXRpb24gYWNyb3NzIE9DUC1jb21wYXRpYmxlIGJhY2tlbmRzCmF1dGhvcjogSmltbXlTaGkyMiAoQEppbW15U2hpMjIpIDxqaW1teXNoaXhpYW5nMjJAZ21haWwuY29tPgpkaXNjdXNzaW9ucy10bzogaHR0cHM6Ly9ldGhlcmV1bS1tYWdpY2lhbnMub3JnL3QvZHJhZnQtZXJjLXVuaXZlcnNhbC1haS1pbmZlcmVuY2UtdmVyaWZpY2F0aW9uLXJlZ2lzdHJ5LzI4MDgzCnN0YXR1czogRHJhZnQKdHlwZTogU3RhbmRhcmRzIFRyYWNrCmNhdGVnb3J5OiBFUkMKY3JlYXRlZDogMjAyNi0wNS0yNgpyZXF1aXJlczogMTY1Ci0tLQoKIyMgQWJzdHJhY3QKClRoaXMgRVJDIGRlZmluZXMgdHdvIG1pbmltYWwgYWJzdHJhY3QgaW50ZXJmYWNlcyBmb3Igb24tY2hhaW4gQUkgaW5mZXJlbmNlIHByb29mIHZlcmlmaWNhdGlvbjoKCi0gYElQcm9vZlZlcmlmaWVyYCDigJQgdGhlIGludGVyZmFjZSB0aGF0IHByb29mIGJhY2tlbmRzIGltcGxlbWVudCB0byBleHBvc2UgYSB1bmlmb3JtIGB2ZXJpZnkoKWAgZW50cnkgcG9pbnQKLSBgSVZlcmlmaWNhdGlvbk1ldGhvZGAg4oCUIHRoZSBpbnRlcmZhY2UgdGhhdCBjb25zdW1pbmcgY29udHJhY3RzIGltcGxlbWVudCB0byBkZWNsYXJlIHdoaWNoIHZlcmlmaWVyIHRoZXkgdXNlCgpgSVByb29mVmVyaWZpZXJgIGlzIGRlc2lnbmVkIGFzIHRoZSBTb2xpZGl0eSBpbnRlcmZhY2UgbGF5ZXIgZm9yIE9DUCAoW09ic2VydmF0aW9uIENvbW1pdG1lbnQgUHJvdG9jb2xdKGh0dHBzOi8vZ2l0aHViLmNvbS9kYW1vbnp3aWNrZXIvb2JzZXJ2YXRpb24tY29tbWl0bWVudC1wcm90b2NvbCkpIGNvbXBhdGlibGUgYmFja2VuZHMuIEVhY2ggYmFja2VuZCBpbXBsZW1lbnRzIE9DUCdzIGNvcmUgdmVyaWZpY2F0aW9uIHByaW1pdGl2ZSDigJQgYHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb25gIOKAlCBmb3IgYSBzcGVjaWZpYyBwcm9vZiBzeXN0ZW0gKHprTUwsIG9wTUwsIFRFRSwgb3JhY2xlLCBtdWx0aXNpZywgZXRjLiksIGFuZCBleHBvc2VzIHRoYXQgaW1wbGVtZW50YXRpb24gdGhyb3VnaCBhIHNpbmdsZSB1bmlmb3JtIGB2ZXJpZnkoKWAgY2FsbC4KClRoaXMgc3RhbmRhcmQgY29tcG9zZXMgd2l0aCBbRVJDLTgwMDRdKC4vZXJjLTgwMDQubWQpIGZvciBhZ2VudCBpZGVudGl0eSBhbmQgW0VSQy04MjYzXShodHRwczovL2dpdGh1Yi5jb20vZXRoZXJldW0vRVJDcy9wdWxsLzE3NDgpIGZvciBvbi1jaGFpbiBwcm9vZiBjb21taXRtZW50LgoKIyMgTW90aXZhdGlvbgoKVmVyaWZpY2F0aW9uIGluZnJhc3RydWN0dXJlIGFscmVhZHkgZXhpc3RzLCBidXQgaXQgaXMgaGlnaGx5IGZyYWdtZW50ZWQuCgoqKlZlcmlmaWNhdGlvbiBQcm9qZWN0cyoqOiBPbi1jaGFpbiBBSSB2ZXJpZmljYXRpb24gaXMgYWxyZWFkeSBsaXZlIGFjcm9zcyBmaXZlIHBhcmFkaWdtczoKCnwgUGFyYWRpZ20gfCBEZXNjcmlwdGlvbiB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgemtNTCB8IENyeXB0b2dyYXBoaWMgcHJvb2YgdGhhdCBhIHNwZWNpZmljIG1vZGVsIHByb2R1Y2VkIGEgZ2l2ZW4gb3V0cHV0IGZyb20gYSBnaXZlbiBpbnB1dCB8Cnwgb3BNTCB8IE9wdGltaXN0aWMgQUkgaW5mZXJlbmNlIGV4ZWN1dGlvbiB3aXRoIGEgY2hhbGxlbmdlIHdpbmRvdyBmb3IgZnJhdWQgcHJvb2ZzIHwKfCBURUUgfCBBSSBpbmZlcmVuY2UgcnVuIGluc2lkZSBhIGhhcmR3YXJlLWlzb2xhdGVkIGVuY2xhdmUgd2l0aCBhIHZlcmlmaWFibGUgYXR0ZXN0YXRpb24gcmVwb3J0IHwKfCBPcmFjbGUgfCBPZmYtY2hhaW4gQUkgaW5mZXJlbmNlIHJlc3VsdCBhdHRlc3RlZCBieSBhIHRydXN0ZWQgc2lnbmVyIG5ldHdvcmsgfAp8IE11bHRpc2lnIC8gQVZTIHwgQUkgaW5mZXJlbmNlIHJlc3VsdCBjb25maXJtZWQgYnkgYSB0aHJlc2hvbGQgb2YgaW5kZXBlbmRlbnQgdmFsaWRhdG9ycyB8CgoqKkVSQ3MqKjogQSBncm93aW5nIHNldCBvZiBFUkNzIGV4cGxpY2l0bHkgbmVlZCBvbi1jaGFpbiBpbmZlcmVuY2UgdmVyaWZpY2F0aW9uLCBidXQgbm9uZSBkZWZpbmUgYSBjb21tb24gaW50ZXJmYWNlIGZvciBpdDoKCi0gKipFUkMtODE4MyoqIChBZ2VudGljIENvbW1lcmNlKSDigJQgZXZhbHVhdG9yICJtYXkgdmVyaWZ5IGEgWksgcHJvb2YiIGJlZm9yZSByZWxlYXNpbmcgcGF5bWVudCwgYnV0IG5vIHZlcmlmaWVyIGludGVyZmFjZSBpcyBkZWZpbmVkCi0gKipFUkMtODAwNCoqIChUcnVzdGxlc3MgQWdlbnRzKSDigJQgVmFsaWRhdGlvbiBSZWdpc3RyeSBsaXN0cyB6a01ML1RFRSB2ZXJpZmllcnMgYXMgZXhhbXBsZXMsIGJ1dCBzcGVjaWZpZXMgbm8gY29udHJhY3QgaW50ZXJmYWNlCi0gKipFUkMtODI2MyoqIChBSSBQcm9vZiBDb21taXRtZW50KSDigJQgZGVmaW5lcyB0aGUgd3JpdGUgcGF0aCBmb3IgYW5jaG9yaW5nIHByb29mIGNvbW1pdG1lbnRzIG9uLWNoYWluLCBidXQgZG9lcyBub3QgZGVmaW5lIGEgY29ycmVzcG9uZGluZyByZWFkL3ZlcmlmeSBpbnRlcmZhY2UKLSAqKkVSQy03OTkyKiogKFZlcmlmaWFibGUgTUwpIOKAlCBkZWZpbmVzIGEgcmVnaXN0cnkgZm9yIFpLIHByb29mcyBvbmx5LCBsZWF2aW5nIG9wTUwsIFRFRSwgT3JhY2xlLCBhbmQgTXVsdGlzaWcgdW5jb3ZlcmVkCi0gKipFUkMtNzAwNyoqIChWZXJpZmlhYmxlIEFJR0MgVG9rZW4pIOKAlCBhY2NlcHRzIG9wYXF1ZSBgYnl0ZXMgcHJvb2ZgIHdpdGggbm8gbW9kZWwgaWRlbnRpZmllciBvciBwcm9vZi1zeXN0ZW0gaWRlbnRpZmllcgoKVGhlIHByb2JsZW06IHRoZXNlIHR3byBzaWRlcyBjYW5ub3QgdGFsayB0byBlYWNoIG90aGVyLiBFdmVyeSBwcm90b2NvbCB0aGF0IG5lZWRzIHZlcmlmaWVkIEFJIGluZmVyZW5jZSB0b2RheSBtdXN0IHdyaXRlIGEgc2VwYXJhdGUgYWRhcHRlciBwZXIgcHJvb2Ygc3lzdGVtIOKAlCByZXN1bHRpbmcgaW4gdmVuZG9yIGxvY2staW4gYW5kIE7Dl00gaW50ZWdyYXRpb24gY29tcGxleGl0eS4gV2hhdCdzIG1pc3NpbmcgaXMgYSBzdGFuZGFyZCB2ZXJpZmllciBpbnRlcmZhY2UgdGhhdCBzaXRzIGluIHRoZSBtaWRkbGUuIFRoaXMgRVJDIHByb3ZpZGVzIGV4YWN0bHkgdGhhdDoKCmBgYApWZXJpZmljYXRpb24gQmFja2VuZHMgICAgICBUaGlzIEVSQyAgICAgICAgICAgICAgICBFUkNzCgogICB6a01MICAgICAgICAgICDilIDilJAgIOKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVlyAg4pSM4pSAIEVSQy04MTgzIChBZ2VudGljIENvbW1lcmNlKQogICBvcE1MICAgICAgICAgICDilIDilKQgIOKVkSAgQUkgSW5mZXJlbmNlICAgIOKVkSAg4pSc4pSAIEVSQy04MDA0IChUcnVzdGxlc3MgQWdlbnRzKQogICBURUUgICAgICAgICAgICDilIDilLzilIDilrrilZEgIFByb29mICAgICAgICAgICDilZHil4TilIDilLzilIAgRVJDLTgyNjMgKEFJIFByb29mIENvbW1pdG1lbnQpCiAgIE9yYWNsZSAgICAgICAgIOKUgOKUpCAg4pWRICBWZXJpZmljYXRpb24gICAg4pWRICDilJzilIAgRVJDLTc5OTIgKFZlcmlmaWFibGUgTUwpCiAgIE11bHRpc2lnIC8gQVZTIOKUgOKUmCAg4pWRICBJbnRlcmZhY2VzICAgICAg4pWRICDilJTilIAgRVJDLTcwMDcgKEFJR0MgVG9rZW4pCiAgICAgICAgICAgICAgICAgICAgICDilZrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZ0KYGBgCgojIyBTcGVjaWZpY2F0aW9uCgpUaGUga2V5IHdvcmRzICJNVVNUIiwgIk1VU1QgTk9UIiwgIlJFUVVJUkVEIiwgIlNIQUxMIiwgIlNIQUxMIE5PVCIsICJTSE9VTEQiLCAiU0hPVUxEIE5PVCIsICJSRUNPTU1FTkRFRCIsICJOT1QgUkVDT01NRU5ERUQiLCAiTUFZIiwgYW5kICJPUFRJT05BTCIgaW4gdGhpcyBkb2N1bWVudCBhcmUgdG8gYmUgaW50ZXJwcmV0ZWQgYXMgZGVzY3JpYmVkIGluIFJGQyAyMTE5IGFuZCBSRkMgODE3NC4KCiMjIyBJUHJvb2ZWZXJpZmllcgoKYGBgc29saWRpdHkKLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKLy8vIEB0aXRsZSBJUHJvb2ZWZXJpZmllcgovLy8gQG5vdGljZSBJbnRlcmZhY2UgZm9yIEFJIGluZmVyZW5jZSBwcm9vZiB2ZXJpZmljYXRpb24gYmFja2VuZHMuCi8vLyBFYWNoIGltcGxlbWVudGF0aW9uIGV4ZWN1dGVzIHRoZSBPQ1AgdmVyaWZpY2F0aW9uIHByaW1pdGl2ZQovLy8gKHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb24pIGZvciBhIHNwZWNpZmljIHByb29mIHN5c3RlbS4KaW50ZXJmYWNlIElQcm9vZlZlcmlmaWVyIHsKICAgIC8vLyBAbm90aWNlIFZlcmlmeSBhbiBBSSBpbmZlcmVuY2UgcHJvb2YuCiAgICAvLy8gQHBhcmFtIGlucHV0SGFzaCAgQ29tbWl0bWVudCB0byB0aGUgbW9kZWwgaW5wdXQgKGUuZy4gU0hBLTI1NiBvciBrZWNjYWsyNTYgZGlnZXN0KS4gSGFzaCBzY2hlbWUgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KICAgIC8vLyBAcGFyYW0gb3V0cHV0SGFzaCBDb21taXRtZW50IHRvIHRoZSBtb2RlbCBvdXRwdXQuIEhhc2ggc2NoZW1lIGlzIGJhY2tlbmQtc3BlY2lmaWMgYW5kIFNIT1VMRCBiZSBkb2N1bWVudGVkIGJ5IGVhY2ggaW1wbGVtZW50YXRpb24uCiAgICAvLy8gQHBhcmFtIG1ldGFkYXRhICAgQmFja2VuZC1zcGVjaWZpYyBjb250ZXh0IChlLmcuIG1vZGVsIGlkZW50aWZpZXIsIGFnZW50IElELCBtYW5pZmVzdCBoYXNoLCB2ZXJzaW9uKQogICAgLy8vIEBwYXJhbSBwcm9vZiAgICAgIEJhY2tlbmQtc3BlY2lmaWMgY3J5cHRvZ3JhcGhpYyBwcm9vZiBieXRlcyAoZS5nLiBaSyBwcm9vZiwgRUlQLTcxMiBzaWduYXR1cmUsIFRFRSBhdHRlc3RhdGlvbikKICAgIC8vLyBAcmV0dXJuICAgICAgICAgICBUcnVlIGlmIHRoZSBwcm9vZiBpcyB2YWxpZCBmb3IgdGhlIGdpdmVuIGlucHV0IGFuZCBvdXRwdXQKICAgIGZ1bmN0aW9uIHZlcmlmeSgKICAgICAgICBieXRlczMyIGlucHV0SGFzaCwKICAgICAgICBieXRlczMyIG91dHB1dEhhc2gsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgbWV0YWRhdGEsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgcHJvb2YKICAgICkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChib29sKTsKCiAgICAvLy8gQG5vdGljZSBDb2xsaXNpb24tcmVzaXN0YW50IHByb2ZpbGUgaWRlbnRpZmllciBmb3IgdGhpcyBiYWNrZW5kLgogICAgLy8vIE1VU1QgZXF1YWwga2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQobmFtZSgpLCB2ZXJzaW9uKCkpKQogICAgZnVuY3Rpb24gcHJvb2ZQcm9maWxlKCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChieXRlczMyKTsKCiAgICAvLy8gQG5vdGljZSBIdW1hbi1yZWFkYWJsZSBwcm9vZiBzeXN0ZW0gbmFtZS4KICAgIC8vLyBSRUNPTU1FTkRFRCBmb3JtYXQ6ICJ7c3lzdGVtfS97dmFyaWFudH0iCiAgICAvLy8gRXhhbXBsZXM6ICJ6a21sL3Jpc2MwIiwgIm9wbWwvb3B0aW1pc3RpYyIsICJ0ZWUvbml0cm8iLCAib3JhY2xlL2F0dGVzdGF0aW9uIgogICAgZnVuY3Rpb24gbmFtZSgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSk7CgogICAgLy8vIEBub3RpY2UgUHJvb2Ygc3lzdGVtIHZlcnNpb24gc3RyaW5nLgogICAgLy8vIEV4YW1wbGVzOiAiMSIsICIyIiwgIjEuMC4wIgogICAgZnVuY3Rpb24gdmVyc2lvbigpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSk7Cn0KYGBgCgojIyMgSVZlcmlmaWNhdGlvbk1ldGhvZAoKYGBgc29saWRpdHkKLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKaW1wb3J0ICIuL0lQcm9vZlZlcmlmaWVyLnNvbCI7CgovLy8gQHRpdGxlIElWZXJpZmljYXRpb25NZXRob2QKLy8vIEBub3RpY2UgSW50ZXJmYWNlIGZvciBjb250cmFjdHMgdGhhdCBkZWNsYXJlIHdoaWNoIHByb29mIHZlcmlmaWVyIHRoZXkgdXNlLgppbnRlcmZhY2UgSVZlcmlmaWNhdGlvbk1ldGhvZCB7CiAgICAvLy8gQG5vdGljZSBSZXR1cm5zIHRoZSBwcm9vZiB2ZXJpZmllciB1c2VkIGJ5IHRoaXMgY29udHJhY3QuCiAgICBmdW5jdGlvbiBnZXRWZXJpZmllcigpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoSVByb29mVmVyaWZpZXIpOwoKICAgIC8vLyBAbm90aWNlIE1VU1QgYmUgZW1pdHRlZCB3aGVuIHRoZSB2ZXJpZmllciBhZGRyZXNzIGNoYW5nZXMuCiAgICBldmVudCBWZXJpZmllclVwZGF0ZWQoCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIHByZXZpb3VzVmVyaWZpZXIsCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIG5ld1ZlcmlmaWVyCiAgICApOwp9CmBgYAoKIyMjIEludGVyZmFjZSBEZXRlY3Rpb24KCkltcGxlbWVudGF0aW9ucyBTSE9VTEQgc3VwcG9ydCBbRVJDLTE2NV0oLi9lcmMtMTY1Lm1kKToKCmBgYHNvbGlkaXR5CmZ1bmN0aW9uIHN1cHBvcnRzSW50ZXJmYWNlKGJ5dGVzNCBpbnRlcmZhY2VJZCkKICAgIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkKewogICAgcmV0dXJuIGludGVyZmFjZUlkID09IHR5cGUoSVByb29mVmVyaWZpZXIpLmludGVyZmFjZUlkCiAgICAgICAgfHwgaW50ZXJmYWNlSWQgPT0gdHlwZShJRVJDMTY1KS5pbnRlcmZhY2VJZDsKfQpgYGAKCiMjIFJhdGlvbmFsZQoKIyMjIE9DUCBhcyB0aGUgVW5pZnlpbmcgUHJpbWl0aXZlCgpBbGwgYElQcm9vZlZlcmlmaWVyYCBpbXBsZW1lbnRhdGlvbnMgTVVTVCBiZSBkZXNpZ25lZCBpbiBhY2NvcmRhbmNlIHdpdGggT0NQIChPYnNlcnZhdGlvbiBDb21taXRtZW50IFByb3RvY29sLCBbZGFtb256d2lja2VyL29ic2VydmF0aW9uLWNvbW1pdG1lbnQtcHJvdG9jb2xdKGh0dHBzOi8vZ2l0aHViLmNvbS9kYW1vbnp3aWNrZXIvb2JzZXJ2YXRpb24tY29tbWl0bWVudC1wcm90b2NvbCkpLiBPQ1AncyBjb3JlIGRlc2lnbiBwcmluY2lwbGUgaXMgdGhhdCB2ZXJpZmljYXRpb24gc2hvdWxkIG5vdCBiZSBsb2NrZWQgdG8gYW55IHNwZWNpZmljIGJsb2NrY2hhaW4sIGNvbnRyYWN0IGludGVyZmFjZSwgb3IgcHJvb2Ygc3lzdGVtIOKAlCBhbnkgaW5kZXBlbmRlbnQgcGFydHkgU0hPVUxEIGJlIGFibGUgdG8gdmVyaWZ5IGEgY29tbWl0bWVudCB1c2luZyBvbmx5IHRoZSBwdWJsaWNseSBhdmFpbGFibGUgb24tY2hhaW4gcmVjb3JkLCB3aXRob3V0IGNhbGxpbmcgYSBzcGVjaWZpYyBjb250cmFjdCBvciBkZXBlbmRpbmcgb24gYW55IHBhcnRpY3VsYXIgaW5mcmFzdHJ1Y3R1cmUuIE9DUCBkZXJpdmVzIGl0cyBjb3JlIHZlcmlmaWNhdGlvbiBwcmltaXRpdmUgZnJvbSB0aGlzIHByaW5jaXBsZToKCmBgYApyZWNvbXB1dGUg4oaSIGNvbXBhcmUg4oaSIGNvbmZpcm0gaW5jbHVzaW9uCmBgYAoKVGhlIGN1cnJlbnQgZml2ZSB2ZXJpZmljYXRpb24gcGFyYWRpZ21zIGFsbCBzYXRpc2Z5IHRoaXMgcHJpbWl0aXZlLCBlYWNoIHdpdGggYSBkaWZmZXJlbnQgdHJ1c3QgbW9kZWw6Cgp8IFBhcmFkaWdtIHwgSG93IE9DUCBwcmltaXRpdmUgaXMgc2F0aXNmaWVkIHwKfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCB6a01MIHwgUmVjb21wdXRlcyB2aWEgWksgY2lyY3VpdDsgY29tcGFyaXNvbiBhbmQgaW5jbHVzaW9uIGNvbmZpcm1lZCBieSBvbi1jaGFpbiBwcm9vZiB2ZXJpZmllciB8Cnwgb3BNTCB8IFJlY29tcHV0ZXMgdmlhIHJlcGxheTsgY29tcGFyaXNvbiBjb25maXJtZWQgYWZ0ZXIgY2hhbGxlbmdlIHdpbmRvdyBjbG9zZXMgfAp8IFRFRSB8IFJlY29tcHV0ZXMgaW5zaWRlIGVuY2xhdmU7IGNvbXBhcmlzb24gYW5kIGluY2x1c2lvbiBjb25maXJtZWQgYnkgYXR0ZXN0YXRpb24gcmVwb3J0IHwKfCBPcmFjbGUgfCBSZWNvbXB1dGVzIG9mZi1jaGFpbjsgY29tcGFyaXNvbiBhbmQgaW5jbHVzaW9uIGNvbmZpcm1lZCBieSBhdHRlc3RlZCBzaWduYXR1cmUgfAp8IE11bHRpc2lnIC8gQVZTIHwgUmVjb21wdXRlcyBhY3Jvc3MgaW5kZXBlbmRlbnQgbm9kZXM7IGNvbXBhcmlzb24gY29uZmlybWVkIGJ5IHRocmVzaG9sZCBhZ2dyZWdhdGUgfAoKQXMgbmV3IHByb29mIHBhcmFkaWdtcyBlbWVyZ2UgaW4gdGhlIGZ1dHVyZSwgdGhleSBhcmUgZXhwZWN0ZWQgdG8gc2F0aXNmeSB0aGUgc2FtZSBPQ1AgcHJpbWl0aXZlIGFuZCBpbXBsZW1lbnQgYElQcm9vZlZlcmlmaWVyYCBhY2NvcmRpbmdseS4gQW55IHZlcmlmaWNhdGlvbiBhcHByb2FjaCB0aGF0IGNhbm5vdCBiZSBleHByZXNzZWQgaW4gdGVybXMgb2YgYHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb25gIGlzIG91dCBvZiBzY29wZSBmb3IgdGhpcyBpbnRlcmZhY2UuCgojIyMgU3RhdGVsZXNzIFZlcmlmaWVyIERlc2lnbgoKYElQcm9vZlZlcmlmaWVyYCBpcyBkZXNpZ25lZCBhcyBhIHN0YXRlbGVzcyBpbnRlcmZhY2U6IHRoZSB2ZXJpZmllciBjb250cmFjdCBob2xkcyBubyBzdGF0ZSBhYm91dCB3aGljaCBtb2RlbCwgYWdlbnQsIG9yIHNlc3Npb24gaXMgYmVpbmcgdmVyaWZpZWQuIEFsbCBjb250ZXh0IG5lY2Vzc2FyeSBmb3IgdmVyaWZpY2F0aW9uIGlzIHBhc3NlZCBpbiB0aHJvdWdoIHRoZSBmdW5jdGlvbiBwYXJhbWV0ZXJzLgoKVGhpcyBpcyBhY2hpZXZlZCBieSB0aGUgZm91ciBwYXJhbWV0ZXJzIG9mIGB2ZXJpZnkoKWAsIGVhY2ggd2l0aCBhIGRpc3RpbmN0IHJvbGU6CgotICoqYGlucHV0SGFzaGAqKiDigJQgYSBgYnl0ZXMzMmAgY29tbWl0bWVudCB0byB0aGUgbW9kZWwgaW5wdXQuIFRoZSBoYXNoIHNjaGVtZSAoU0hBLTI1Niwga2VjY2FrMjU2LCBvciBvdGhlcikgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KLSAqKmBvdXRwdXRIYXNoYCoqIOKAlCBhIGBieXRlczMyYCBjb21taXRtZW50IHRvIHRoZSBtb2RlbCBvdXRwdXQuIEhhc2ggc2NoZW1lIGlzIGJhY2tlbmQtc3BlY2lmaWMgYW5kIFNIT1VMRCBiZSBkb2N1bWVudGVkIGJ5IGVhY2ggaW1wbGVtZW50YXRpb24uCi0gKipgbWV0YWRhdGFgKiog4oCUIGJhY2tlbmQtc3BlY2lmaWMgc2VtYW50aWMgY29udGV4dDogbW9kZWwgaWRlbnRpZmllciwgYWdlbnQgSUQsIG1hbmlmZXN0IGhhc2gsIHZlcnNpb24sIHJlZ2lzdHJ5IHJlZmVyZW5jZSwgb3IgYW55IG90aGVyIGZpZWxkcyBuZWVkZWQgdG8gaWRlbnRpZnkgKndoYXQqIHdhcyB2ZXJpZmllZC4gVGhlIGVuY29kaW5nIG9mIGBtZXRhZGF0YWAgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KLSAqKmBwcm9vZmAqKiDigJQgYmFja2VuZC1zcGVjaWZpYyBjcnlwdG9ncmFwaGljIG1hdGVyaWFsOiB0aGUgWksgcHJvb2YsIEVJUC03MTIgc2lnbmF0dXJlLCBURUUgYXR0ZXN0YXRpb24gcmVwb3J0LCBvciBtdWx0aXNpZyBhZ2dyZWdhdGUg4oCUIHRoZSBkYXRhIG5lZWRlZCB0byAqY29uZmlybSogdGhlIHZlcmlmaWNhdGlvbiBjbGFpbS4KClRoaXMgc2VwYXJhdGlvbiBhbGxvd3MgdG9vbGluZyBhbmQgY29uc3VtZXJzIHRvIGluc3BlY3Qgc2VtYW50aWMgY29udGV4dCAodmlhIGBtZXRhZGF0YWApIHdpdGhvdXQgbmVlZGluZyB0byBwYXJzZSBwcm9vZi1zeXN0ZW0tc3BlY2lmaWMgY3J5cHRvZ3JhcGhpYyBmb3JtYXRzIChpbiBgcHJvb2ZgKS4gSXQgYWxzbyBtZWFucyBhIHNpbmdsZSBkZXBsb3llZCBgSVByb29mVmVyaWZpZXJgIGluc3RhbmNlIGNhbiBzZXJ2ZSBhcyBhIHZlcmlmaWVyIGZvciBtdWx0aXBsZSBtb2RlbHMgb3IgYWdlbnRzIHdpdGhvdXQgcmVkZXBsb3ltZW50LgoKYG1ldGFkYXRhYCBpcyB0eXBlZCBhcyBgYnl0ZXMgY2FsbGRhdGFgIHJhdGhlciB0aGFuIGBieXRlczMyYCBkZWxpYmVyYXRlbHkuIEEgYGJ5dGVzMzJgIGhhc2ggc3VwcG9ydHMgZXF1YWxpdHkgY2hlY2tzIGJ1dCBjYW5ub3Qgc3VwcG9ydCBvcmRlcmluZyBjb21wYXJpc29ucyAoYD5gLCBgPGAsIGA+PWApLiBWZXJpZmllciBpbXBsZW1lbnRhdGlvbnMgY29tbW9ubHkgbmVlZCB0byBkZWNvZGUgaW5kaXZpZHVhbCBmaWVsZHMgZnJvbSBgbWV0YWRhdGFgIGZvciBvcmRlcmluZyBsb2dpYyDigJQgZm9yIGV4YW1wbGUsIGNvbXBhcmluZyB0aW1lc3RhbXBzIGZvciBmcmVzaG5lc3MgYm91bmRzLCBjaGVja2luZyBub25jZXMgZm9yIHJlcGxheSBwcmV2ZW50aW9uLCBvciBlbmZvcmNpbmcgbWluaW11bSB2ZXJzaW9uIHJlcXVpcmVtZW50cy4gRWFjaCBgSVByb29mVmVyaWZpZXJgIGltcGxlbWVudGF0aW9uIFNIT1VMRCBkb2N1bWVudCBpdHMgZXhwZWN0ZWQgYG1ldGFkYXRhYCBlbmNvZGluZy4gVHlwaWNhbCBmaWVsZHMgYnkgcGFyYWRpZ206CgotICoqemtNTCoqOiBjaXJjdWl0IGlkZW50aWZpZXIsIG1vZGVsIGNvbW1pdG1lbnQsIGNpcmN1aXQgdmVyc2lvbgotICoqb3BNTCoqOiByZXF1ZXN0IGlkZW50aWZpZXIsIGNoYWxsZW5nZSBkZWFkbGluZSwgc3VibWl0dGVyIGFkZHJlc3MKLSAqKlRFRSoqOiBlbmNsYXZlIGlkZW50aWZpZXIsIFBDUiB2YWx1ZXMsIHZhbGlkaXR5IGRlYWRsaW5lCi0gKipPcmFjbGUgLyBhdHRlc3RhdGlvbioqOiBzdWJtaXNzaW9uIGRlYWRsaW5lLCBzaWduZXIgcmVnaXN0cnkgYWRkcmVzcywgYWdlbnQgaWRlbnRpZmllcgotICoqTXVsdGlzaWcgLyBBVlMqKjogcXVvcnVtIGlkZW50aWZpZXIsIHNpZ25pbmcgZXBvY2gsIHZhbGlkYXRvciBzZXQgY29tbWl0bWVudAoKIyMjIElucHV0IFByb3ZlbmFuY2UKCk9uLWNoYWluIEFJIGFnZW50cyB0eXBpY2FsbHkgY29uc3RydWN0IHRoZWlyIGlucHV0cyBieSByZWFkaW5nIGZyb20gZXh0ZXJuYWwgc291cmNlcyDigJQgRU5TIHJlY29yZHMsIE5GVCBtZXRhZGF0YSwgb3JhY2xlIGZlZWRzLCBvciBjb250cmFjdCByZXR1cm4gdmFsdWVzIOKAlCBhbmQgYXBwbHlpbmcgcHJlcHJvY2Vzc2luZyBydWxlcyBiZWZvcmUgdGhlIGRhdGEgaXMgcGFzc2VkIHRvIHRoZSBtb2RlbC4gVGhpcyBtZWFucyBgaW5wdXRIYXNoYCBhbG9uZSBjYXJyaWVzIG5vIHRydXN0d29ydGhpbmVzcyBndWFyYW50ZWUg4oCUIGl0IGlzIGEgY29tbWl0bWVudCB0byB3aGF0ZXZlciBpbnB1dCB3YXMgcHJvdmlkZWQsIGJ1dCBzYXlzIG5vdGhpbmcgYWJvdXQgd2hlcmUgdGhhdCBpbnB1dCBjYW1lIGZyb20gb3IgaG93IGl0IHdhcyBkZXJpdmVkLiBBIHZlcmlmaWVyIGNvbmZpcm1zICJ0aGlzIG1vZGVsIHByb2R1Y2VkIHRoaXMgb3V0cHV0IGZyb20gdGhpcyBpbnB1dCIgYnV0IGNhbm5vdCBjb25maXJtIHdoZXRoZXIgdGhlIGlucHV0IGl0c2VsZiB3YXMgbGVnaXRpbWF0ZS4KClRoaXMgZ2FwIGlzIGFkZHJlc3NlZCBieSBbV1lSSVdFXShodHRwczovL2dpdGh1Yi5jb20vVE1lcmxpbmkvd3lyaXdlKSAoV2hhdCBZb3UgUmVhZCBJcyBXaGF0IEV4ZWN1dGVkKS4gV1lSSVdFIGV4dGVuZHMgdGhlIHNpbmdsZSBgaW5wdXRIYXNoYCBpbnRvIGEgdGhyZWUtY29tbWl0bWVudCBzY2hlbWUgY292ZXJpbmcgdGhlIHJhdyBpbnB1dCwgdGhlIHNhbml0aXphdGlvbiBwaXBlbGluZSBhcHBsaWVkIHRvIGl0LCBhbmQgdGhlIHNhbml0aXplZCBpbnB1dCB0aGF0IHdhcyBhY3R1YWxseSBleGVjdXRlZCDigJQgYWxsb3dpbmcgYW4gaW5kZXBlbmRlbnQgdmVyaWZpZXIgdG8gY29uZmlybSB0aGF0IHRoZSBpbnB1dCBwYXNzZWQgdG8gdGhlIG1vZGVsIGlzIGRlcml2ZWQgZnJvbSBhIGtub3duIHNvdXJjZSB0aHJvdWdoIGEga25vd24sIGNvbW1pdHRlZCBwaXBlbGluZS4KCkNvbnN1bWVycyB0aGF0IHJlcXVpcmUgaW5wdXQgcHJvdmVuYW5jZSBndWFyYW50ZWVzIGFyZSBSRUNPTU1FTkRFRCB0byBhZG9wdCB0aGUgV1lSSVdFIGFwcHJvYWNoIGFsb25nc2lkZSBgdmVyaWZ5KClgLiBUaGlzIEVSQyBkb2VzIG5vdCBwcmVzY3JpYmUgaG93IGBpbnB1dEhhc2hgIHdhcyBkZXJpdmVkLgoKIyMjIHByb29mUHJvZmlsZSwgbmFtZSwgYW5kIHZlcnNpb24KClNpbmNlIG11bHRpcGxlIE9DUC1jb21wYXRpYmxlIGltcGxlbWVudGF0aW9ucyBtYXkgY29leGlzdCwgY29uc3VtZXJzIG5lZWQgYSB3YXkgdG8gaWRlbnRpZnkgd2hpY2ggcGFyYWRpZ20gYSBnaXZlbiB2ZXJpZmllciB1c2VzIG9uLWNoYWluLiBObyBjZW50cmFsIHJlZ2lzdHJ5IGlzIHJlcXVpcmVkIOKAlCBzZWxmLWFzc2lnbmVkIGBuYW1lKClgIHN0cmluZ3MgYXJlIHN1ZmZpY2llbnQgZm9yIHRoZSBlY29zeXN0ZW0gdG8gY29vcmRpbmF0ZSBpbmZvcm1hbGx5LCB0aGUgc2FtZSB3YXkgRVJDLTIwIGBzeW1ib2woKWAgd29ya3MgaW4gcHJhY3RpY2UuCgpgcHJvb2ZQcm9maWxlKClgIHJldHVybnMgYGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKG5hbWUoKSwgdmVyc2lvbigpKSlgIGFzIGEgY29sbGlzaW9uLXJlc2lzdGFudCBgYnl0ZXMzMmAgaWRlbnRpZmllciBmb3Igb24tY2hhaW4gY29tcGFyaXNvbiwgYXZvaWRpbmcgdGhlIGNvc3QgYW5kIGNvbGxpc2lvbiByaXNrIG9mIHJhdyBzdHJpbmcgY29tcGFyaXNvbiBhdCBzY2FsZS4gYG5hbWUoKWAgYW5kIGB2ZXJzaW9uKClgIGFyZSBleHBvc2VkIHNlcGFyYXRlbHkgc28gb2ZmLWNoYWluIHRvb2xpbmcgY2FuIGRpc3BsYXkgaHVtYW4tcmVhZGFibGUgbGFiZWxzIHdpdGhvdXQgcGFyc2luZyBgYnl0ZXMzMmAuCgojIyMgUmVsYXRpb25zaGlwIHRvIEVSQy04MjYzCgpFUkMtODI2MyBkZWZpbmVzIHRoZSB3cml0ZSBwYXRoOiBhbiBhZ2VudCBhbmNob3JzIGEgcHJvb2YgY29tbWl0bWVudCBvbi1jaGFpbiB2aWEgYGFuY2hvcihhZ2VudElkU2NoZW1lLCBhZ2VudElkLCBwcm9vZkhhc2gpYC4gVGhpcyBFUkMgZGVmaW5lcyB0aGUgcmVhZCBwYXRoOiBhIGNvbnN1bWVyIHZlcmlmaWVzIHRoYXQgY29tbWl0bWVudCB2aWEgYHZlcmlmeShpbnB1dENvbW1pdG1lbnQsIG91dHB1dENvbW1pdG1lbnQsIHByb29mKWAuCgpUaGUgYGlucHV0Q29tbWl0bWVudGAgcGFyYW1ldGVyIGluIGB2ZXJpZnkoKWAgY29ycmVzcG9uZHMgdG8gdGhlIGBwcm9vZkhhc2hgIHVzZWQgaW4gdGhlIEVSQy04MjYzIGBhbmNob3IoKWAgY2FsbCBmb3IgdGhlIHNhbWUgaW5mZXJlbmNlIGV2ZW50LiBCb3RoIGNvbW1pdCB0byB0aGUgbW9kZWwgaW5wdXQgYXMgcHJlc2VudGVkIHRvIHRoZSBwcm9vZiBzeXN0ZW0uIFRoZSBoYXNoIHNjaGVtZSAoU0hBLTI1Niwga2VjY2FrMjU2LCBvciBvdGhlcikgaXMgZGV0ZXJtaW5lZCBieSB0aGUgYmFja2VuZCBhbmQgU0hPVUxEIGJlIGNvbnNpc3RlbnQgYmV0d2VlbiB0aGUgYGFuY2hvcigpYCBhbmQgYHZlcmlmeSgpYCBjYWxscy4gVGhlc2UgdHdvIEVSQ3MgYXJlIGNvbXBsZW1lbnRhcnk6IEVSQy04MjYzIGlzIHRoZSBjb21taXRtZW50IGxheWVyLCB0aGlzIEVSQyBpcyB0aGUgdmVyaWZpY2F0aW9uIGxheWVyLgoKIyMgQmFja3dhcmRzIENvbXBhdGliaWxpdHkKCk5vIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGlzc3Vlcy4gVGhpcyBFUkMgaW50cm9kdWNlcyBuZXcgaW50ZXJmYWNlcyBhbmQgZG9lcyBub3QgbW9kaWZ5IGFueSBleGlzdGluZyBzdGFuZGFyZC4KCiMjIFJlZmVyZW5jZSBJbXBsZW1lbnRhdGlvbgoKPiBUbyBiZSBjb250cmlidXRlZC4gQW50aWNpcGF0ZWQgaW1wbGVtZW50YXRpb25zOgo+IC0gemtNTCBiYWNrZW5kIChSSVNDIFplcm8gLyBCb25zYWkpCj4gLSBvcE1MIG9wdGltaXN0aWMgYmFja2VuZAo+IC0gVEVFIGJhY2tlbmQgKEFXUyBOaXRybyAvIEludGVsIFREWCkKPiAtIE9yYWNsZSAvIG11bHRpc2lnIGJhY2tlbmQKCiMjIFNlY3VyaXR5IENvbnNpZGVyYXRpb25zCgoqKklucHV0IHRydXN0d29ydGhpbmVzcyoqCgpgdmVyaWZ5KClgIGNvbmZpcm1zIHRoYXQgYSBwcm9vZiBpcyB2YWxpZCBmb3IgYSBnaXZlbiBgaW5wdXRDb21taXRtZW50YC4gSXQgZG9lcyBub3QgY29uZmlybSB0aGF0IHRoZSBpbnB1dCBpdHNlbGYgd2FzIHRydXN0d29ydGh5IG9yIGNvcnJlY3RseSBkZXJpdmVkLiBJbnB1dCBzYW5pdGlzYXRpb24gYW5kIHByb3ZlbmFuY2UgYXJlIHRoZSByZXNwb25zaWJpbGl0eSBvZiB0aGUgbGF5ZXIgYWJvdmUuIENvbnN1bWVycyB0aGF0IHJlcXVpcmUgaW5wdXQgcHJvdmVuYW5jZSBndWFyYW50ZWVzIFNIT1VMRCB2ZXJpZnkgdGhlIGlucHV0IGNvbW1pdG1lbnQgaW5kZXBlbmRlbnRseSBiZWZvcmUgYWNjZXB0aW5nIGEgcHJvb2YuCgoqKk9wYXF1ZSBwcm9vZiBieXRlcyoqCgpDb25zdW1lcnMgTVVTVCBOT1QgYXNzdW1lIHN0cnVjdHVyYWwgY29tcGF0aWJpbGl0eSBvZiBgcHJvb2ZgIGJ5dGVzIGFjcm9zcyBkaWZmZXJlbnQgYElQcm9vZlZlcmlmaWVyYCBpbXBsZW1lbnRhdGlvbnMuIFBhc3NpbmcgcHJvb2YgYnl0ZXMgZnJvbSBvbmUgYmFja2VuZCB0byBhIGRpZmZlcmVudCBiYWNrZW5kJ3MgdmVyaWZpZXIgTVVTVCBOT1QgYmUgdHJlYXRlZCBhcyBzYWZlLgoKKipWZXJpZmllciBtdXRhYmlsaXR5KioKCmBnZXRWZXJpZmllcigpYCBNQVkgcmV0dXJuIGRpZmZlcmVudCBhZGRyZXNzZXMgb3ZlciB0aW1lLiBIaWdoLXZhbHVlIGNvbnN1bWVycyBTSE9VTEQgbW9uaXRvciBgVmVyaWZpZXJVcGRhdGVkYCBldmVudHMgYW5kIHRyZWF0IHZlcmlmaWVyIGNoYW5nZXMgYXMgc2VjdXJpdHktcmVsZXZhbnQgY29uZmlndXJhdGlvbiBjaGFuZ2VzLgoKKipObyBsaXZlbmVzcyBndWFyYW50ZWUqKgoKYHZlcmlmeSgpYCBpcyBhIGB2aWV3YCBmdW5jdGlvbi4gSXQgcHJvdmlkZXMgbm8gZ3VhcmFudGVlIHRoYXQgdGhlIHVuZGVybHlpbmcgcHJvb2Ygc3lzdGVtIGlzIGxpdmUgb3IgdGhhdCB0aGUgbW9kZWwgcmVmZXJyZWQgdG8gYnkgYGlucHV0Q29tbWl0bWVudGAgaXMgYXZhaWxhYmxlLgoKIyMgQ29weXJpZ2h0CgpDb3B5cmlnaHQgYW5kIHJlbGF0ZWQgcmlnaHRzIHdhaXZlZCB2aWEgW0NDMF0oLi4vTElDRU5TRS5tZCkuCg== \ No newline at end of file From 69f4d64b3e43fce4f098d14b64a813234e062792 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Thu, 28 May 2026 17:19:21 +0800 Subject: [PATCH 15/40] fix: replace double-base64 encoded content with correct plain text --- ERCS/erc-8274.md | 228 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 49eda2779dc..63fa7dda392 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -1 +1,227 @@ -LS0tCmVpcDogODI3NAp0aXRsZTogQUkgSW5mZXJlbmNlIFByb29mIFZlcmlmaWNhdGlvbiBJbnRlcmZhY2VzCmRlc2NyaXB0aW9uOiBNaW5pbWFsIGFic3RyYWN0IGludGVyZmFjZXMgZm9yIG9uLWNoYWluIEFJIGluZmVyZW5jZSBwcm9vZiB2ZXJpZmljYXRpb24gYWNyb3NzIE9DUC1jb21wYXRpYmxlIGJhY2tlbmRzCmF1dGhvcjogSmltbXlTaGkyMiAoQEppbW15U2hpMjIpIDxqaW1teXNoaXhpYW5nMjJAZ21haWwuY29tPgpkaXNjdXNzaW9ucy10bzogaHR0cHM6Ly9ldGhlcmV1bS1tYWdpY2lhbnMub3JnL3QvZHJhZnQtZXJjLXVuaXZlcnNhbC1haS1pbmZlcmVuY2UtdmVyaWZpY2F0aW9uLXJlZ2lzdHJ5LzI4MDgzCnN0YXR1czogRHJhZnQKdHlwZTogU3RhbmRhcmRzIFRyYWNrCmNhdGVnb3J5OiBFUkMKY3JlYXRlZDogMjAyNi0wNS0yNgpyZXF1aXJlczogMTY1Ci0tLQoKIyMgQWJzdHJhY3QKClRoaXMgRVJDIGRlZmluZXMgdHdvIG1pbmltYWwgYWJzdHJhY3QgaW50ZXJmYWNlcyBmb3Igb24tY2hhaW4gQUkgaW5mZXJlbmNlIHByb29mIHZlcmlmaWNhdGlvbjoKCi0gYElQcm9vZlZlcmlmaWVyYCDigJQgdGhlIGludGVyZmFjZSB0aGF0IHByb29mIGJhY2tlbmRzIGltcGxlbWVudCB0byBleHBvc2UgYSB1bmlmb3JtIGB2ZXJpZnkoKWAgZW50cnkgcG9pbnQKLSBgSVZlcmlmaWNhdGlvbk1ldGhvZGAg4oCUIHRoZSBpbnRlcmZhY2UgdGhhdCBjb25zdW1pbmcgY29udHJhY3RzIGltcGxlbWVudCB0byBkZWNsYXJlIHdoaWNoIHZlcmlmaWVyIHRoZXkgdXNlCgpgSVByb29mVmVyaWZpZXJgIGlzIGRlc2lnbmVkIGFzIHRoZSBTb2xpZGl0eSBpbnRlcmZhY2UgbGF5ZXIgZm9yIE9DUCAoW09ic2VydmF0aW9uIENvbW1pdG1lbnQgUHJvdG9jb2xdKGh0dHBzOi8vZ2l0aHViLmNvbS9kYW1vbnp3aWNrZXIvb2JzZXJ2YXRpb24tY29tbWl0bWVudC1wcm90b2NvbCkpIGNvbXBhdGlibGUgYmFja2VuZHMuIEVhY2ggYmFja2VuZCBpbXBsZW1lbnRzIE9DUCdzIGNvcmUgdmVyaWZpY2F0aW9uIHByaW1pdGl2ZSDigJQgYHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb25gIOKAlCBmb3IgYSBzcGVjaWZpYyBwcm9vZiBzeXN0ZW0gKHprTUwsIG9wTUwsIFRFRSwgb3JhY2xlLCBtdWx0aXNpZywgZXRjLiksIGFuZCBleHBvc2VzIHRoYXQgaW1wbGVtZW50YXRpb24gdGhyb3VnaCBhIHNpbmdsZSB1bmlmb3JtIGB2ZXJpZnkoKWAgY2FsbC4KClRoaXMgc3RhbmRhcmQgY29tcG9zZXMgd2l0aCBbRVJDLTgwMDRdKC4vZXJjLTgwMDQubWQpIGZvciBhZ2VudCBpZGVudGl0eSBhbmQgW0VSQy04MjYzXShodHRwczovL2dpdGh1Yi5jb20vZXRoZXJldW0vRVJDcy9wdWxsLzE3NDgpIGZvciBvbi1jaGFpbiBwcm9vZiBjb21taXRtZW50LgoKIyMgTW90aXZhdGlvbgoKVmVyaWZpY2F0aW9uIGluZnJhc3RydWN0dXJlIGFscmVhZHkgZXhpc3RzLCBidXQgaXQgaXMgaGlnaGx5IGZyYWdtZW50ZWQuCgoqKlZlcmlmaWNhdGlvbiBQcm9qZWN0cyoqOiBPbi1jaGFpbiBBSSB2ZXJpZmljYXRpb24gaXMgYWxyZWFkeSBsaXZlIGFjcm9zcyBmaXZlIHBhcmFkaWdtczoKCnwgUGFyYWRpZ20gfCBEZXNjcmlwdGlvbiB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgemtNTCB8IENyeXB0b2dyYXBoaWMgcHJvb2YgdGhhdCBhIHNwZWNpZmljIG1vZGVsIHByb2R1Y2VkIGEgZ2l2ZW4gb3V0cHV0IGZyb20gYSBnaXZlbiBpbnB1dCB8Cnwgb3BNTCB8IE9wdGltaXN0aWMgQUkgaW5mZXJlbmNlIGV4ZWN1dGlvbiB3aXRoIGEgY2hhbGxlbmdlIHdpbmRvdyBmb3IgZnJhdWQgcHJvb2ZzIHwKfCBURUUgfCBBSSBpbmZlcmVuY2UgcnVuIGluc2lkZSBhIGhhcmR3YXJlLWlzb2xhdGVkIGVuY2xhdmUgd2l0aCBhIHZlcmlmaWFibGUgYXR0ZXN0YXRpb24gcmVwb3J0IHwKfCBPcmFjbGUgfCBPZmYtY2hhaW4gQUkgaW5mZXJlbmNlIHJlc3VsdCBhdHRlc3RlZCBieSBhIHRydXN0ZWQgc2lnbmVyIG5ldHdvcmsgfAp8IE11bHRpc2lnIC8gQVZTIHwgQUkgaW5mZXJlbmNlIHJlc3VsdCBjb25maXJtZWQgYnkgYSB0aHJlc2hvbGQgb2YgaW5kZXBlbmRlbnQgdmFsaWRhdG9ycyB8CgoqKkVSQ3MqKjogQSBncm93aW5nIHNldCBvZiBFUkNzIGV4cGxpY2l0bHkgbmVlZCBvbi1jaGFpbiBpbmZlcmVuY2UgdmVyaWZpY2F0aW9uLCBidXQgbm9uZSBkZWZpbmUgYSBjb21tb24gaW50ZXJmYWNlIGZvciBpdDoKCi0gKipFUkMtODE4MyoqIChBZ2VudGljIENvbW1lcmNlKSDigJQgZXZhbHVhdG9yICJtYXkgdmVyaWZ5IGEgWksgcHJvb2YiIGJlZm9yZSByZWxlYXNpbmcgcGF5bWVudCwgYnV0IG5vIHZlcmlmaWVyIGludGVyZmFjZSBpcyBkZWZpbmVkCi0gKipFUkMtODAwNCoqIChUcnVzdGxlc3MgQWdlbnRzKSDigJQgVmFsaWRhdGlvbiBSZWdpc3RyeSBsaXN0cyB6a01ML1RFRSB2ZXJpZmllcnMgYXMgZXhhbXBsZXMsIGJ1dCBzcGVjaWZpZXMgbm8gY29udHJhY3QgaW50ZXJmYWNlCi0gKipFUkMtODI2MyoqIChBSSBQcm9vZiBDb21taXRtZW50KSDigJQgZGVmaW5lcyB0aGUgd3JpdGUgcGF0aCBmb3IgYW5jaG9yaW5nIHByb29mIGNvbW1pdG1lbnRzIG9uLWNoYWluLCBidXQgZG9lcyBub3QgZGVmaW5lIGEgY29ycmVzcG9uZGluZyByZWFkL3ZlcmlmeSBpbnRlcmZhY2UKLSAqKkVSQy03OTkyKiogKFZlcmlmaWFibGUgTUwpIOKAlCBkZWZpbmVzIGEgcmVnaXN0cnkgZm9yIFpLIHByb29mcyBvbmx5LCBsZWF2aW5nIG9wTUwsIFRFRSwgT3JhY2xlLCBhbmQgTXVsdGlzaWcgdW5jb3ZlcmVkCi0gKipFUkMtNzAwNyoqIChWZXJpZmlhYmxlIEFJR0MgVG9rZW4pIOKAlCBhY2NlcHRzIG9wYXF1ZSBgYnl0ZXMgcHJvb2ZgIHdpdGggbm8gbW9kZWwgaWRlbnRpZmllciBvciBwcm9vZi1zeXN0ZW0gaWRlbnRpZmllcgoKVGhlIHByb2JsZW06IHRoZXNlIHR3byBzaWRlcyBjYW5ub3QgdGFsayB0byBlYWNoIG90aGVyLiBFdmVyeSBwcm90b2NvbCB0aGF0IG5lZWRzIHZlcmlmaWVkIEFJIGluZmVyZW5jZSB0b2RheSBtdXN0IHdyaXRlIGEgc2VwYXJhdGUgYWRhcHRlciBwZXIgcHJvb2Ygc3lzdGVtIOKAlCByZXN1bHRpbmcgaW4gdmVuZG9yIGxvY2staW4gYW5kIE7Dl00gaW50ZWdyYXRpb24gY29tcGxleGl0eS4gV2hhdCdzIG1pc3NpbmcgaXMgYSBzdGFuZGFyZCB2ZXJpZmllciBpbnRlcmZhY2UgdGhhdCBzaXRzIGluIHRoZSBtaWRkbGUuIFRoaXMgRVJDIHByb3ZpZGVzIGV4YWN0bHkgdGhhdDoKCmBgYApWZXJpZmljYXRpb24gQmFja2VuZHMgICAgICBUaGlzIEVSQyAgICAgICAgICAgICAgICBFUkNzCgogICB6a01MICAgICAgICAgICDilIDilJAgIOKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVlyAg4pSM4pSAIEVSQy04MTgzIChBZ2VudGljIENvbW1lcmNlKQogICBvcE1MICAgICAgICAgICDilIDilKQgIOKVkSAgQUkgSW5mZXJlbmNlICAgIOKVkSAg4pSc4pSAIEVSQy04MDA0IChUcnVzdGxlc3MgQWdlbnRzKQogICBURUUgICAgICAgICAgICDilIDilLzilIDilrrilZEgIFByb29mICAgICAgICAgICDilZHil4TilIDilLzilIAgRVJDLTgyNjMgKEFJIFByb29mIENvbW1pdG1lbnQpCiAgIE9yYWNsZSAgICAgICAgIOKUgOKUpCAg4pWRICBWZXJpZmljYXRpb24gICAg4pWRICDilJzilIAgRVJDLTc5OTIgKFZlcmlmaWFibGUgTUwpCiAgIE11bHRpc2lnIC8gQVZTIOKUgOKUmCAg4pWRICBJbnRlcmZhY2VzICAgICAg4pWRICDilJTilIAgRVJDLTcwMDcgKEFJR0MgVG9rZW4pCiAgICAgICAgICAgICAgICAgICAgICDilZrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZ0KYGBgCgojIyBTcGVjaWZpY2F0aW9uCgpUaGUga2V5IHdvcmRzICJNVVNUIiwgIk1VU1QgTk9UIiwgIlJFUVVJUkVEIiwgIlNIQUxMIiwgIlNIQUxMIE5PVCIsICJTSE9VTEQiLCAiU0hPVUxEIE5PVCIsICJSRUNPTU1FTkRFRCIsICJOT1QgUkVDT01NRU5ERUQiLCAiTUFZIiwgYW5kICJPUFRJT05BTCIgaW4gdGhpcyBkb2N1bWVudCBhcmUgdG8gYmUgaW50ZXJwcmV0ZWQgYXMgZGVzY3JpYmVkIGluIFJGQyAyMTE5IGFuZCBSRkMgODE3NC4KCiMjIyBJUHJvb2ZWZXJpZmllcgoKYGBgc29saWRpdHkKLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKLy8vIEB0aXRsZSBJUHJvb2ZWZXJpZmllcgovLy8gQG5vdGljZSBJbnRlcmZhY2UgZm9yIEFJIGluZmVyZW5jZSBwcm9vZiB2ZXJpZmljYXRpb24gYmFja2VuZHMuCi8vLyBFYWNoIGltcGxlbWVudGF0aW9uIGV4ZWN1dGVzIHRoZSBPQ1AgdmVyaWZpY2F0aW9uIHByaW1pdGl2ZQovLy8gKHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb24pIGZvciBhIHNwZWNpZmljIHByb29mIHN5c3RlbS4KaW50ZXJmYWNlIElQcm9vZlZlcmlmaWVyIHsKICAgIC8vLyBAbm90aWNlIFZlcmlmeSBhbiBBSSBpbmZlcmVuY2UgcHJvb2YuCiAgICAvLy8gQHBhcmFtIGlucHV0SGFzaCAgQ29tbWl0bWVudCB0byB0aGUgbW9kZWwgaW5wdXQgKGUuZy4gU0hBLTI1NiBvciBrZWNjYWsyNTYgZGlnZXN0KS4gSGFzaCBzY2hlbWUgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KICAgIC8vLyBAcGFyYW0gb3V0cHV0SGFzaCBDb21taXRtZW50IHRvIHRoZSBtb2RlbCBvdXRwdXQuIEhhc2ggc2NoZW1lIGlzIGJhY2tlbmQtc3BlY2lmaWMgYW5kIFNIT1VMRCBiZSBkb2N1bWVudGVkIGJ5IGVhY2ggaW1wbGVtZW50YXRpb24uCiAgICAvLy8gQHBhcmFtIG1ldGFkYXRhICAgQmFja2VuZC1zcGVjaWZpYyBjb250ZXh0IChlLmcuIG1vZGVsIGlkZW50aWZpZXIsIGFnZW50IElELCBtYW5pZmVzdCBoYXNoLCB2ZXJzaW9uKQogICAgLy8vIEBwYXJhbSBwcm9vZiAgICAgIEJhY2tlbmQtc3BlY2lmaWMgY3J5cHRvZ3JhcGhpYyBwcm9vZiBieXRlcyAoZS5nLiBaSyBwcm9vZiwgRUlQLTcxMiBzaWduYXR1cmUsIFRFRSBhdHRlc3RhdGlvbikKICAgIC8vLyBAcmV0dXJuICAgICAgICAgICBUcnVlIGlmIHRoZSBwcm9vZiBpcyB2YWxpZCBmb3IgdGhlIGdpdmVuIGlucHV0IGFuZCBvdXRwdXQKICAgIGZ1bmN0aW9uIHZlcmlmeSgKICAgICAgICBieXRlczMyIGlucHV0SGFzaCwKICAgICAgICBieXRlczMyIG91dHB1dEhhc2gsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgbWV0YWRhdGEsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgcHJvb2YKICAgICkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChib29sKTsKCiAgICAvLy8gQG5vdGljZSBDb2xsaXNpb24tcmVzaXN0YW50IHByb2ZpbGUgaWRlbnRpZmllciBmb3IgdGhpcyBiYWNrZW5kLgogICAgLy8vIE1VU1QgZXF1YWwga2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQobmFtZSgpLCB2ZXJzaW9uKCkpKQogICAgZnVuY3Rpb24gcHJvb2ZQcm9maWxlKCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChieXRlczMyKTsKCiAgICAvLy8gQG5vdGljZSBIdW1hbi1yZWFkYWJsZSBwcm9vZiBzeXN0ZW0gbmFtZS4KICAgIC8vLyBSRUNPTU1FTkRFRCBmb3JtYXQ6ICJ7c3lzdGVtfS97dmFyaWFudH0iCiAgICAvLy8gRXhhbXBsZXM6ICJ6a21sL3Jpc2MwIiwgIm9wbWwvb3B0aW1pc3RpYyIsICJ0ZWUvbml0cm8iLCAib3JhY2xlL2F0dGVzdGF0aW9uIgogICAgZnVuY3Rpb24gbmFtZSgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSk7CgogICAgLy8vIEBub3RpY2UgUHJvb2Ygc3lzdGVtIHZlcnNpb24gc3RyaW5nLgogICAgLy8vIEV4YW1wbGVzOiAiMSIsICIyIiwgIjEuMC4wIgogICAgZnVuY3Rpb24gdmVyc2lvbigpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSk7Cn0KYGBgCgojIyMgSVZlcmlmaWNhdGlvbk1ldGhvZAoKYGBgc29saWRpdHkKLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKaW1wb3J0ICIuL0lQcm9vZlZlcmlmaWVyLnNvbCI7CgovLy8gQHRpdGxlIElWZXJpZmljYXRpb25NZXRob2QKLy8vIEBub3RpY2UgSW50ZXJmYWNlIGZvciBjb250cmFjdHMgdGhhdCBkZWNsYXJlIHdoaWNoIHByb29mIHZlcmlmaWVyIHRoZXkgdXNlLgppbnRlcmZhY2UgSVZlcmlmaWNhdGlvbk1ldGhvZCB7CiAgICAvLy8gQG5vdGljZSBSZXR1cm5zIHRoZSBwcm9vZiB2ZXJpZmllciB1c2VkIGJ5IHRoaXMgY29udHJhY3QuCiAgICBmdW5jdGlvbiBnZXRWZXJpZmllcigpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoSVByb29mVmVyaWZpZXIpOwoKICAgIC8vLyBAbm90aWNlIE1VU1QgYmUgZW1pdHRlZCB3aGVuIHRoZSB2ZXJpZmllciBhZGRyZXNzIGNoYW5nZXMuCiAgICBldmVudCBWZXJpZmllclVwZGF0ZWQoCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIHByZXZpb3VzVmVyaWZpZXIsCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIG5ld1ZlcmlmaWVyCiAgICApOwp9CmBgYAoKIyMjIEludGVyZmFjZSBEZXRlY3Rpb24KCkltcGxlbWVudGF0aW9ucyBTSE9VTEQgc3VwcG9ydCBbRVJDLTE2NV0oLi9lcmMtMTY1Lm1kKToKCmBgYHNvbGlkaXR5CmZ1bmN0aW9uIHN1cHBvcnRzSW50ZXJmYWNlKGJ5dGVzNCBpbnRlcmZhY2VJZCkKICAgIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkKewogICAgcmV0dXJuIGludGVyZmFjZUlkID09IHR5cGUoSVByb29mVmVyaWZpZXIpLmludGVyZmFjZUlkCiAgICAgICAgfHwgaW50ZXJmYWNlSWQgPT0gdHlwZShJRVJDMTY1KS5pbnRlcmZhY2VJZDsKfQpgYGAKCiMjIFJhdGlvbmFsZQoKIyMjIE9DUCBhcyB0aGUgVW5pZnlpbmcgUHJpbWl0aXZlCgpBbGwgYElQcm9vZlZlcmlmaWVyYCBpbXBsZW1lbnRhdGlvbnMgTVVTVCBiZSBkZXNpZ25lZCBpbiBhY2NvcmRhbmNlIHdpdGggT0NQIChPYnNlcnZhdGlvbiBDb21taXRtZW50IFByb3RvY29sLCBbZGFtb256d2lja2VyL29ic2VydmF0aW9uLWNvbW1pdG1lbnQtcHJvdG9jb2xdKGh0dHBzOi8vZ2l0aHViLmNvbS9kYW1vbnp3aWNrZXIvb2JzZXJ2YXRpb24tY29tbWl0bWVudC1wcm90b2NvbCkpLiBPQ1AncyBjb3JlIGRlc2lnbiBwcmluY2lwbGUgaXMgdGhhdCB2ZXJpZmljYXRpb24gc2hvdWxkIG5vdCBiZSBsb2NrZWQgdG8gYW55IHNwZWNpZmljIGJsb2NrY2hhaW4sIGNvbnRyYWN0IGludGVyZmFjZSwgb3IgcHJvb2Ygc3lzdGVtIOKAlCBhbnkgaW5kZXBlbmRlbnQgcGFydHkgU0hPVUxEIGJlIGFibGUgdG8gdmVyaWZ5IGEgY29tbWl0bWVudCB1c2luZyBvbmx5IHRoZSBwdWJsaWNseSBhdmFpbGFibGUgb24tY2hhaW4gcmVjb3JkLCB3aXRob3V0IGNhbGxpbmcgYSBzcGVjaWZpYyBjb250cmFjdCBvciBkZXBlbmRpbmcgb24gYW55IHBhcnRpY3VsYXIgaW5mcmFzdHJ1Y3R1cmUuIE9DUCBkZXJpdmVzIGl0cyBjb3JlIHZlcmlmaWNhdGlvbiBwcmltaXRpdmUgZnJvbSB0aGlzIHByaW5jaXBsZToKCmBgYApyZWNvbXB1dGUg4oaSIGNvbXBhcmUg4oaSIGNvbmZpcm0gaW5jbHVzaW9uCmBgYAoKVGhlIGN1cnJlbnQgZml2ZSB2ZXJpZmljYXRpb24gcGFyYWRpZ21zIGFsbCBzYXRpc2Z5IHRoaXMgcHJpbWl0aXZlLCBlYWNoIHdpdGggYSBkaWZmZXJlbnQgdHJ1c3QgbW9kZWw6Cgp8IFBhcmFkaWdtIHwgSG93IE9DUCBwcmltaXRpdmUgaXMgc2F0aXNmaWVkIHwKfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCB6a01MIHwgUmVjb21wdXRlcyB2aWEgWksgY2lyY3VpdDsgY29tcGFyaXNvbiBhbmQgaW5jbHVzaW9uIGNvbmZpcm1lZCBieSBvbi1jaGFpbiBwcm9vZiB2ZXJpZmllciB8Cnwgb3BNTCB8IFJlY29tcHV0ZXMgdmlhIHJlcGxheTsgY29tcGFyaXNvbiBjb25maXJtZWQgYWZ0ZXIgY2hhbGxlbmdlIHdpbmRvdyBjbG9zZXMgfAp8IFRFRSB8IFJlY29tcHV0ZXMgaW5zaWRlIGVuY2xhdmU7IGNvbXBhcmlzb24gYW5kIGluY2x1c2lvbiBjb25maXJtZWQgYnkgYXR0ZXN0YXRpb24gcmVwb3J0IHwKfCBPcmFjbGUgfCBSZWNvbXB1dGVzIG9mZi1jaGFpbjsgY29tcGFyaXNvbiBhbmQgaW5jbHVzaW9uIGNvbmZpcm1lZCBieSBhdHRlc3RlZCBzaWduYXR1cmUgfAp8IE11bHRpc2lnIC8gQVZTIHwgUmVjb21wdXRlcyBhY3Jvc3MgaW5kZXBlbmRlbnQgbm9kZXM7IGNvbXBhcmlzb24gY29uZmlybWVkIGJ5IHRocmVzaG9sZCBhZ2dyZWdhdGUgfAoKQXMgbmV3IHByb29mIHBhcmFkaWdtcyBlbWVyZ2UgaW4gdGhlIGZ1dHVyZSwgdGhleSBhcmUgZXhwZWN0ZWQgdG8gc2F0aXNmeSB0aGUgc2FtZSBPQ1AgcHJpbWl0aXZlIGFuZCBpbXBsZW1lbnQgYElQcm9vZlZlcmlmaWVyYCBhY2NvcmRpbmdseS4gQW55IHZlcmlmaWNhdGlvbiBhcHByb2FjaCB0aGF0IGNhbm5vdCBiZSBleHByZXNzZWQgaW4gdGVybXMgb2YgYHJlY29tcHV0ZSDihpIgY29tcGFyZSDihpIgY29uZmlybSBpbmNsdXNpb25gIGlzIG91dCBvZiBzY29wZSBmb3IgdGhpcyBpbnRlcmZhY2UuCgojIyMgU3RhdGVsZXNzIFZlcmlmaWVyIERlc2lnbgoKYElQcm9vZlZlcmlmaWVyYCBpcyBkZXNpZ25lZCBhcyBhIHN0YXRlbGVzcyBpbnRlcmZhY2U6IHRoZSB2ZXJpZmllciBjb250cmFjdCBob2xkcyBubyBzdGF0ZSBhYm91dCB3aGljaCBtb2RlbCwgYWdlbnQsIG9yIHNlc3Npb24gaXMgYmVpbmcgdmVyaWZpZWQuIEFsbCBjb250ZXh0IG5lY2Vzc2FyeSBmb3IgdmVyaWZpY2F0aW9uIGlzIHBhc3NlZCBpbiB0aHJvdWdoIHRoZSBmdW5jdGlvbiBwYXJhbWV0ZXJzLgoKVGhpcyBpcyBhY2hpZXZlZCBieSB0aGUgZm91ciBwYXJhbWV0ZXJzIG9mIGB2ZXJpZnkoKWAsIGVhY2ggd2l0aCBhIGRpc3RpbmN0IHJvbGU6CgotICoqYGlucHV0SGFzaGAqKiDigJQgYSBgYnl0ZXMzMmAgY29tbWl0bWVudCB0byB0aGUgbW9kZWwgaW5wdXQuIFRoZSBoYXNoIHNjaGVtZSAoU0hBLTI1Niwga2VjY2FrMjU2LCBvciBvdGhlcikgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KLSAqKmBvdXRwdXRIYXNoYCoqIOKAlCBhIGBieXRlczMyYCBjb21taXRtZW50IHRvIHRoZSBtb2RlbCBvdXRwdXQuIEhhc2ggc2NoZW1lIGlzIGJhY2tlbmQtc3BlY2lmaWMgYW5kIFNIT1VMRCBiZSBkb2N1bWVudGVkIGJ5IGVhY2ggaW1wbGVtZW50YXRpb24uCi0gKipgbWV0YWRhdGFgKiog4oCUIGJhY2tlbmQtc3BlY2lmaWMgc2VtYW50aWMgY29udGV4dDogbW9kZWwgaWRlbnRpZmllciwgYWdlbnQgSUQsIG1hbmlmZXN0IGhhc2gsIHZlcnNpb24sIHJlZ2lzdHJ5IHJlZmVyZW5jZSwgb3IgYW55IG90aGVyIGZpZWxkcyBuZWVkZWQgdG8gaWRlbnRpZnkgKndoYXQqIHdhcyB2ZXJpZmllZC4gVGhlIGVuY29kaW5nIG9mIGBtZXRhZGF0YWAgaXMgYmFja2VuZC1zcGVjaWZpYyBhbmQgU0hPVUxEIGJlIGRvY3VtZW50ZWQgYnkgZWFjaCBpbXBsZW1lbnRhdGlvbi4KLSAqKmBwcm9vZmAqKiDigJQgYmFja2VuZC1zcGVjaWZpYyBjcnlwdG9ncmFwaGljIG1hdGVyaWFsOiB0aGUgWksgcHJvb2YsIEVJUC03MTIgc2lnbmF0dXJlLCBURUUgYXR0ZXN0YXRpb24gcmVwb3J0LCBvciBtdWx0aXNpZyBhZ2dyZWdhdGUg4oCUIHRoZSBkYXRhIG5lZWRlZCB0byAqY29uZmlybSogdGhlIHZlcmlmaWNhdGlvbiBjbGFpbS4KClRoaXMgc2VwYXJhdGlvbiBhbGxvd3MgdG9vbGluZyBhbmQgY29uc3VtZXJzIHRvIGluc3BlY3Qgc2VtYW50aWMgY29udGV4dCAodmlhIGBtZXRhZGF0YWApIHdpdGhvdXQgbmVlZGluZyB0byBwYXJzZSBwcm9vZi1zeXN0ZW0tc3BlY2lmaWMgY3J5cHRvZ3JhcGhpYyBmb3JtYXRzIChpbiBgcHJvb2ZgKS4gSXQgYWxzbyBtZWFucyBhIHNpbmdsZSBkZXBsb3llZCBgSVByb29mVmVyaWZpZXJgIGluc3RhbmNlIGNhbiBzZXJ2ZSBhcyBhIHZlcmlmaWVyIGZvciBtdWx0aXBsZSBtb2RlbHMgb3IgYWdlbnRzIHdpdGhvdXQgcmVkZXBsb3ltZW50LgoKYG1ldGFkYXRhYCBpcyB0eXBlZCBhcyBgYnl0ZXMgY2FsbGRhdGFgIHJhdGhlciB0aGFuIGBieXRlczMyYCBkZWxpYmVyYXRlbHkuIEEgYGJ5dGVzMzJgIGhhc2ggc3VwcG9ydHMgZXF1YWxpdHkgY2hlY2tzIGJ1dCBjYW5ub3Qgc3VwcG9ydCBvcmRlcmluZyBjb21wYXJpc29ucyAoYD5gLCBgPGAsIGA+PWApLiBWZXJpZmllciBpbXBsZW1lbnRhdGlvbnMgY29tbW9ubHkgbmVlZCB0byBkZWNvZGUgaW5kaXZpZHVhbCBmaWVsZHMgZnJvbSBgbWV0YWRhdGFgIGZvciBvcmRlcmluZyBsb2dpYyDigJQgZm9yIGV4YW1wbGUsIGNvbXBhcmluZyB0aW1lc3RhbXBzIGZvciBmcmVzaG5lc3MgYm91bmRzLCBjaGVja2luZyBub25jZXMgZm9yIHJlcGxheSBwcmV2ZW50aW9uLCBvciBlbmZvcmNpbmcgbWluaW11bSB2ZXJzaW9uIHJlcXVpcmVtZW50cy4gRWFjaCBgSVByb29mVmVyaWZpZXJgIGltcGxlbWVudGF0aW9uIFNIT1VMRCBkb2N1bWVudCBpdHMgZXhwZWN0ZWQgYG1ldGFkYXRhYCBlbmNvZGluZy4gVHlwaWNhbCBmaWVsZHMgYnkgcGFyYWRpZ206CgotICoqemtNTCoqOiBjaXJjdWl0IGlkZW50aWZpZXIsIG1vZGVsIGNvbW1pdG1lbnQsIGNpcmN1aXQgdmVyc2lvbgotICoqb3BNTCoqOiByZXF1ZXN0IGlkZW50aWZpZXIsIGNoYWxsZW5nZSBkZWFkbGluZSwgc3VibWl0dGVyIGFkZHJlc3MKLSAqKlRFRSoqOiBlbmNsYXZlIGlkZW50aWZpZXIsIFBDUiB2YWx1ZXMsIHZhbGlkaXR5IGRlYWRsaW5lCi0gKipPcmFjbGUgLyBhdHRlc3RhdGlvbioqOiBzdWJtaXNzaW9uIGRlYWRsaW5lLCBzaWduZXIgcmVnaXN0cnkgYWRkcmVzcywgYWdlbnQgaWRlbnRpZmllcgotICoqTXVsdGlzaWcgLyBBVlMqKjogcXVvcnVtIGlkZW50aWZpZXIsIHNpZ25pbmcgZXBvY2gsIHZhbGlkYXRvciBzZXQgY29tbWl0bWVudAoKIyMjIElucHV0IFByb3ZlbmFuY2UKCk9uLWNoYWluIEFJIGFnZW50cyB0eXBpY2FsbHkgY29uc3RydWN0IHRoZWlyIGlucHV0cyBieSByZWFkaW5nIGZyb20gZXh0ZXJuYWwgc291cmNlcyDigJQgRU5TIHJlY29yZHMsIE5GVCBtZXRhZGF0YSwgb3JhY2xlIGZlZWRzLCBvciBjb250cmFjdCByZXR1cm4gdmFsdWVzIOKAlCBhbmQgYXBwbHlpbmcgcHJlcHJvY2Vzc2luZyBydWxlcyBiZWZvcmUgdGhlIGRhdGEgaXMgcGFzc2VkIHRvIHRoZSBtb2RlbC4gVGhpcyBtZWFucyBgaW5wdXRIYXNoYCBhbG9uZSBjYXJyaWVzIG5vIHRydXN0d29ydGhpbmVzcyBndWFyYW50ZWUg4oCUIGl0IGlzIGEgY29tbWl0bWVudCB0byB3aGF0ZXZlciBpbnB1dCB3YXMgcHJvdmlkZWQsIGJ1dCBzYXlzIG5vdGhpbmcgYWJvdXQgd2hlcmUgdGhhdCBpbnB1dCBjYW1lIGZyb20gb3IgaG93IGl0IHdhcyBkZXJpdmVkLiBBIHZlcmlmaWVyIGNvbmZpcm1zICJ0aGlzIG1vZGVsIHByb2R1Y2VkIHRoaXMgb3V0cHV0IGZyb20gdGhpcyBpbnB1dCIgYnV0IGNhbm5vdCBjb25maXJtIHdoZXRoZXIgdGhlIGlucHV0IGl0c2VsZiB3YXMgbGVnaXRpbWF0ZS4KClRoaXMgZ2FwIGlzIGFkZHJlc3NlZCBieSBbV1lSSVdFXShodHRwczovL2dpdGh1Yi5jb20vVE1lcmxpbmkvd3lyaXdlKSAoV2hhdCBZb3UgUmVhZCBJcyBXaGF0IEV4ZWN1dGVkKS4gV1lSSVdFIGV4dGVuZHMgdGhlIHNpbmdsZSBgaW5wdXRIYXNoYCBpbnRvIGEgdGhyZWUtY29tbWl0bWVudCBzY2hlbWUgY292ZXJpbmcgdGhlIHJhdyBpbnB1dCwgdGhlIHNhbml0aXphdGlvbiBwaXBlbGluZSBhcHBsaWVkIHRvIGl0LCBhbmQgdGhlIHNhbml0aXplZCBpbnB1dCB0aGF0IHdhcyBhY3R1YWxseSBleGVjdXRlZCDigJQgYWxsb3dpbmcgYW4gaW5kZXBlbmRlbnQgdmVyaWZpZXIgdG8gY29uZmlybSB0aGF0IHRoZSBpbnB1dCBwYXNzZWQgdG8gdGhlIG1vZGVsIGlzIGRlcml2ZWQgZnJvbSBhIGtub3duIHNvdXJjZSB0aHJvdWdoIGEga25vd24sIGNvbW1pdHRlZCBwaXBlbGluZS4KCkNvbnN1bWVycyB0aGF0IHJlcXVpcmUgaW5wdXQgcHJvdmVuYW5jZSBndWFyYW50ZWVzIGFyZSBSRUNPTU1FTkRFRCB0byBhZG9wdCB0aGUgV1lSSVdFIGFwcHJvYWNoIGFsb25nc2lkZSBgdmVyaWZ5KClgLiBUaGlzIEVSQyBkb2VzIG5vdCBwcmVzY3JpYmUgaG93IGBpbnB1dEhhc2hgIHdhcyBkZXJpdmVkLgoKIyMjIHByb29mUHJvZmlsZSwgbmFtZSwgYW5kIHZlcnNpb24KClNpbmNlIG11bHRpcGxlIE9DUC1jb21wYXRpYmxlIGltcGxlbWVudGF0aW9ucyBtYXkgY29leGlzdCwgY29uc3VtZXJzIG5lZWQgYSB3YXkgdG8gaWRlbnRpZnkgd2hpY2ggcGFyYWRpZ20gYSBnaXZlbiB2ZXJpZmllciB1c2VzIG9uLWNoYWluLiBObyBjZW50cmFsIHJlZ2lzdHJ5IGlzIHJlcXVpcmVkIOKAlCBzZWxmLWFzc2lnbmVkIGBuYW1lKClgIHN0cmluZ3MgYXJlIHN1ZmZpY2llbnQgZm9yIHRoZSBlY29zeXN0ZW0gdG8gY29vcmRpbmF0ZSBpbmZvcm1hbGx5LCB0aGUgc2FtZSB3YXkgRVJDLTIwIGBzeW1ib2woKWAgd29ya3MgaW4gcHJhY3RpY2UuCgpgcHJvb2ZQcm9maWxlKClgIHJldHVybnMgYGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKG5hbWUoKSwgdmVyc2lvbigpKSlgIGFzIGEgY29sbGlzaW9uLXJlc2lzdGFudCBgYnl0ZXMzMmAgaWRlbnRpZmllciBmb3Igb24tY2hhaW4gY29tcGFyaXNvbiwgYXZvaWRpbmcgdGhlIGNvc3QgYW5kIGNvbGxpc2lvbiByaXNrIG9mIHJhdyBzdHJpbmcgY29tcGFyaXNvbiBhdCBzY2FsZS4gYG5hbWUoKWAgYW5kIGB2ZXJzaW9uKClgIGFyZSBleHBvc2VkIHNlcGFyYXRlbHkgc28gb2ZmLWNoYWluIHRvb2xpbmcgY2FuIGRpc3BsYXkgaHVtYW4tcmVhZGFibGUgbGFiZWxzIHdpdGhvdXQgcGFyc2luZyBgYnl0ZXMzMmAuCgojIyMgUmVsYXRpb25zaGlwIHRvIEVSQy04MjYzCgpFUkMtODI2MyBkZWZpbmVzIHRoZSB3cml0ZSBwYXRoOiBhbiBhZ2VudCBhbmNob3JzIGEgcHJvb2YgY29tbWl0bWVudCBvbi1jaGFpbiB2aWEgYGFuY2hvcihhZ2VudElkU2NoZW1lLCBhZ2VudElkLCBwcm9vZkhhc2gpYC4gVGhpcyBFUkMgZGVmaW5lcyB0aGUgcmVhZCBwYXRoOiBhIGNvbnN1bWVyIHZlcmlmaWVzIHRoYXQgY29tbWl0bWVudCB2aWEgYHZlcmlmeShpbnB1dENvbW1pdG1lbnQsIG91dHB1dENvbW1pdG1lbnQsIHByb29mKWAuCgpUaGUgYGlucHV0Q29tbWl0bWVudGAgcGFyYW1ldGVyIGluIGB2ZXJpZnkoKWAgY29ycmVzcG9uZHMgdG8gdGhlIGBwcm9vZkhhc2hgIHVzZWQgaW4gdGhlIEVSQy04MjYzIGBhbmNob3IoKWAgY2FsbCBmb3IgdGhlIHNhbWUgaW5mZXJlbmNlIGV2ZW50LiBCb3RoIGNvbW1pdCB0byB0aGUgbW9kZWwgaW5wdXQgYXMgcHJlc2VudGVkIHRvIHRoZSBwcm9vZiBzeXN0ZW0uIFRoZSBoYXNoIHNjaGVtZSAoU0hBLTI1Niwga2VjY2FrMjU2LCBvciBvdGhlcikgaXMgZGV0ZXJtaW5lZCBieSB0aGUgYmFja2VuZCBhbmQgU0hPVUxEIGJlIGNvbnNpc3RlbnQgYmV0d2VlbiB0aGUgYGFuY2hvcigpYCBhbmQgYHZlcmlmeSgpYCBjYWxscy4gVGhlc2UgdHdvIEVSQ3MgYXJlIGNvbXBsZW1lbnRhcnk6IEVSQy04MjYzIGlzIHRoZSBjb21taXRtZW50IGxheWVyLCB0aGlzIEVSQyBpcyB0aGUgdmVyaWZpY2F0aW9uIGxheWVyLgoKIyMgQmFja3dhcmRzIENvbXBhdGliaWxpdHkKCk5vIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGlzc3Vlcy4gVGhpcyBFUkMgaW50cm9kdWNlcyBuZXcgaW50ZXJmYWNlcyBhbmQgZG9lcyBub3QgbW9kaWZ5IGFueSBleGlzdGluZyBzdGFuZGFyZC4KCiMjIFJlZmVyZW5jZSBJbXBsZW1lbnRhdGlvbgoKPiBUbyBiZSBjb250cmlidXRlZC4gQW50aWNpcGF0ZWQgaW1wbGVtZW50YXRpb25zOgo+IC0gemtNTCBiYWNrZW5kIChSSVNDIFplcm8gLyBCb25zYWkpCj4gLSBvcE1MIG9wdGltaXN0aWMgYmFja2VuZAo+IC0gVEVFIGJhY2tlbmQgKEFXUyBOaXRybyAvIEludGVsIFREWCkKPiAtIE9yYWNsZSAvIG11bHRpc2lnIGJhY2tlbmQKCiMjIFNlY3VyaXR5IENvbnNpZGVyYXRpb25zCgoqKklucHV0IHRydXN0d29ydGhpbmVzcyoqCgpgdmVyaWZ5KClgIGNvbmZpcm1zIHRoYXQgYSBwcm9vZiBpcyB2YWxpZCBmb3IgYSBnaXZlbiBgaW5wdXRDb21taXRtZW50YC4gSXQgZG9lcyBub3QgY29uZmlybSB0aGF0IHRoZSBpbnB1dCBpdHNlbGYgd2FzIHRydXN0d29ydGh5IG9yIGNvcnJlY3RseSBkZXJpdmVkLiBJbnB1dCBzYW5pdGlzYXRpb24gYW5kIHByb3ZlbmFuY2UgYXJlIHRoZSByZXNwb25zaWJpbGl0eSBvZiB0aGUgbGF5ZXIgYWJvdmUuIENvbnN1bWVycyB0aGF0IHJlcXVpcmUgaW5wdXQgcHJvdmVuYW5jZSBndWFyYW50ZWVzIFNIT1VMRCB2ZXJpZnkgdGhlIGlucHV0IGNvbW1pdG1lbnQgaW5kZXBlbmRlbnRseSBiZWZvcmUgYWNjZXB0aW5nIGEgcHJvb2YuCgoqKk9wYXF1ZSBwcm9vZiBieXRlcyoqCgpDb25zdW1lcnMgTVVTVCBOT1QgYXNzdW1lIHN0cnVjdHVyYWwgY29tcGF0aWJpbGl0eSBvZiBgcHJvb2ZgIGJ5dGVzIGFjcm9zcyBkaWZmZXJlbnQgYElQcm9vZlZlcmlmaWVyYCBpbXBsZW1lbnRhdGlvbnMuIFBhc3NpbmcgcHJvb2YgYnl0ZXMgZnJvbSBvbmUgYmFja2VuZCB0byBhIGRpZmZlcmVudCBiYWNrZW5kJ3MgdmVyaWZpZXIgTVVTVCBOT1QgYmUgdHJlYXRlZCBhcyBzYWZlLgoKKipWZXJpZmllciBtdXRhYmlsaXR5KioKCmBnZXRWZXJpZmllcigpYCBNQVkgcmV0dXJuIGRpZmZlcmVudCBhZGRyZXNzZXMgb3ZlciB0aW1lLiBIaWdoLXZhbHVlIGNvbnN1bWVycyBTSE9VTEQgbW9uaXRvciBgVmVyaWZpZXJVcGRhdGVkYCBldmVudHMgYW5kIHRyZWF0IHZlcmlmaWVyIGNoYW5nZXMgYXMgc2VjdXJpdHktcmVsZXZhbnQgY29uZmlndXJhdGlvbiBjaGFuZ2VzLgoKKipObyBsaXZlbmVzcyBndWFyYW50ZWUqKgoKYHZlcmlmeSgpYCBpcyBhIGB2aWV3YCBmdW5jdGlvbi4gSXQgcHJvdmlkZXMgbm8gZ3VhcmFudGVlIHRoYXQgdGhlIHVuZGVybHlpbmcgcHJvb2Ygc3lzdGVtIGlzIGxpdmUgb3IgdGhhdCB0aGUgbW9kZWwgcmVmZXJyZWQgdG8gYnkgYGlucHV0Q29tbWl0bWVudGAgaXMgYXZhaWxhYmxlLgoKIyMgQ29weXJpZ2h0CgpDb3B5cmlnaHQgYW5kIHJlbGF0ZWQgcmlnaHRzIHdhaXZlZCB2aWEgW0NDMF0oLi4vTElDRU5TRS5tZCkuCg== \ No newline at end of file +--- +eip: 8274 +title: AI Inference Proof Verification Interfaces +description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends +author: JimmyShi22 (@JimmyShi22) +discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 +status: Draft +type: Standards Track +category: ERC +created: 2026-05-26 +requires: 165 +--- + +## Abstract + +This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: + +- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point +- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use + +`IProofVerifier` is designed as the Solidity interface layer for OCP ([Observation Commitment Protocol](https://github.com/damonzwicker/observation-commitment-protocol)) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. + +This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](https://github.com/ethereum/ERCs/pull/1748) for on-chain proof commitment. + +## Motivation + +Verification infrastructure already exists, but it is highly fragmented. + +**Verification Projects**: On-chain AI verification is already live across five paradigms: + +| Paradigm | Description | +|----------|-------------| +| zkML | Cryptographic proof that a specific model produced a given output from a given input | +| opML | Optimistic AI inference execution with a challenge window for fraud proofs | +| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | +| Oracle | Off-chain AI inference result attested by a trusted signer network | +| Multisig / AVS | AI inference result confirmed by a threshold of independent validators | + +**ERCs**: A growing set of ERCs explicitly need on-chain inference verification, but none define a common interface for it: + +- **ERC-8183** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined +- **ERC-8004** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface +- **ERC-8263** (AI Proof Commitment) — defines the write path for anchoring proof commitments on-chain, but does not define a corresponding read/verify interface +- **ERC-7992** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered +- **ERC-7007** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier + +The problem: these two sides cannot talk to each other. Every protocol that needs verified AI inference today must write a separate adapter per proof system — resulting in vendor lock-in and N×M integration complexity. What's missing is a standard verifier interface that sits in the middle. This ERC provides exactly that: + +``` +Verification Backends This ERC ERCs + + zkML ─┐ ╔══════════════════╗ ┌─ ERC-8183 (Agentic Commerce) + opML ─┤ ║ AI Inference ║ ├─ ERC-8004 (Trustless Agents) + TEE ─┼─►║ Proof ║◄─┼─ ERC-8263 (AI Proof Commitment) + Oracle ─┤ ║ Verification ║ ├─ ERC-7992 (Verifiable ML) + Multisig / AVS ─┘ ║ Interfaces ║ └─ ERC-7007 (AIGC Token) + ╚══════════════════╝ +``` + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### IProofVerifier + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title IProofVerifier +/// @notice Interface for AI inference proof verification backends. +/// Each implementation executes the OCP verification primitive +/// (recompute → compare → confirm inclusion) for a specific proof system. +interface IProofVerifier { + /// @notice Verify an AI inference proof. + /// @param inputHash Commitment to the model input (e.g. SHA-256 or keccak256 digest). Hash scheme is backend-specific and SHOULD be documented by each implementation. + /// @param outputHash Commitment to the model output. Hash scheme is backend-specific and SHOULD be documented by each implementation. + /// @param metadata Backend-specific context (e.g. model identifier, agent ID, manifest hash, version) + /// @param proof Backend-specific cryptographic proof bytes (e.g. ZK proof, EIP-712 signature, TEE attestation) + /// @return True if the proof is valid for the given input and output + function verify( + bytes32 inputHash, + bytes32 outputHash, + bytes calldata metadata, + bytes calldata proof + ) external view returns (bool); + + /// @notice Collision-resistant profile identifier for this backend. + /// MUST equal keccak256(abi.encodePacked(name(), version())) + function proofProfile() external view returns (bytes32); + + /// @notice Human-readable proof system name. + /// RECOMMENDED format: "{system}/{variant}" + /// Examples: "zkml/risc0", "opml/optimistic", "tee/nitro", "oracle/attestation" + function name() external view returns (string memory); + + /// @notice Proof system version string. + /// Examples: "1", "2", "1.0.0" + function version() external view returns (string memory); +} +``` + +### IVerificationMethod + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title IVerificationMethod +/// @notice Interface for contracts that declare which proof verifier they use. +interface IVerificationMethod { + /// @notice Returns the proof verifier used by this contract. + function getVerifier() external view returns (IProofVerifier); + + /// @notice MUST be emitted when the verifier address changes. + event VerifierUpdated( + address indexed previousVerifier, + address indexed newVerifier + ); +} +``` + +### Interface Detection + +Implementations SHOULD support [ERC-165](./erc-165.md): + +```solidity +function supportsInterface(bytes4 interfaceId) + external view returns (bool) +{ + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} +``` + +## Rationale + +### OCP as the Unifying Primitive + +All `IProofVerifier` implementations MUST be designed in accordance with OCP (Observation Commitment Protocol, [damonzwicker/observation-commitment-protocol](https://github.com/damonzwicker/observation-commitment-protocol)). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: + +``` +recompute → compare → confirm inclusion +``` + +The current five verification paradigms all satisfy this primitive, each with a different trust model: + +| Paradigm | How OCP primitive is satisfied | +|----------|-------------------------------| +| zkML | Recomputes via ZK circuit; comparison and inclusion confirmed by on-chain proof verifier | +| opML | Recomputes via replay; comparison confirmed after challenge window closes | +| TEE | Recomputes inside enclave; comparison and inclusion confirmed by attestation report | +| Oracle | Recomputes off-chain; comparison and inclusion confirmed by attested signature | +| Multisig / AVS | Recomputes across independent nodes; comparison confirmed by threshold aggregate | + +As new proof paradigms emerge in the future, they are expected to satisfy the same OCP primitive and implement `IProofVerifier` accordingly. Any verification approach that cannot be expressed in terms of `recompute → compare → confirm inclusion` is out of scope for this interface. + +### Stateless Verifier Design + +`IProofVerifier` is designed as a stateless interface: the verifier contract holds no state about which model, agent, or session is being verified. All context necessary for verification is passed in through the function parameters. + +This is achieved by the four parameters of `verify()`, each with a distinct role: + +- **`inputHash`** — a `bytes32` commitment to the model input. The hash scheme (SHA-256, keccak256, or other) is backend-specific and SHOULD be documented by each implementation. +- **`outputHash`** — a `bytes32` commitment to the model output. Hash scheme is backend-specific and SHOULD be documented by each implementation. +- **`metadata`** — backend-specific semantic context: model identifier, agent ID, manifest hash, version, registry reference, or any other fields needed to identify *what* was verified. The encoding of `metadata` is backend-specific and SHOULD be documented by each implementation. +- **`proof`** — backend-specific cryptographic material: the ZK proof, EIP-712 signature, TEE attestation report, or multisig aggregate — the data needed to *confirm* the verification claim. + +This separation allows tooling and consumers to inspect semantic context (via `metadata`) without needing to parse proof-system-specific cryptographic formats (in `proof`). It also means a single deployed `IProofVerifier` instance can serve as a verifier for multiple models or agents without redeployment. + +`metadata` is typed as `bytes calldata` rather than `bytes32` deliberately. A `bytes32` hash supports equality checks but cannot support ordering comparisons (`>`, `<`, `>=`). Verifier implementations commonly need to decode individual fields from `metadata` for ordering logic — for example, comparing timestamps for freshness bounds, checking nonces for replay prevention, or enforcing minimum version requirements. Each `IProofVerifier` implementation SHOULD document its expected `metadata` encoding. Typical fields by paradigm: + +- **zkML**: circuit identifier, model commitment, circuit version +- **opML**: request identifier, challenge deadline, submitter address +- **TEE**: enclave identifier, PCR values, validity deadline +- **Oracle / attestation**: submission deadline, signer registry address, agent identifier +- **Multisig / AVS**: quorum identifier, signing epoch, validator set commitment + +### Input Provenance + +On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. + +This gap is addressed by [WYRIWE](https://github.com/TMerlini/wyriwe) (What You Read Is What Executed). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. + +Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. + +### Relationship to ERC-8263 + +ERC-8263 defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, metadata, proof)`. + +The `inputHash` parameter in `verify()` corresponds to the `proofHash` used in the ERC-8263 `anchor()` call for the same inference event. Both commit to the model input as presented to the proof system. The hash scheme (SHA-256, keccak256, or other) is determined by the backend and SHOULD be consistent between the `anchor()` and `verify()` calls. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. + +## Backwards Compatibility + +No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. + +## Reference Implementation + +> To be contributed. Anticipated implementations: +> - zkML backend (RISC Zero / Bonsai) +> - opML optimistic backend +> - TEE backend (AWS Nitro / Intel TDX) +> - Oracle / multisig backend + +## Security Considerations + +**Input trustworthiness** + +`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input hash independently before accepting a proof. + +**Opaque proof bytes** + +Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. + +**Verifier mutability** + +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. + +**No liveness guarantee** + +`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 78e51aa6a36520693b52a4ccd243a0dc66e1b5f6 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Thu, 28 May 2026 17:25:29 +0800 Subject: [PATCH 16/40] =?UTF-8?q?fix:=20resolve=20eipw=20CI=20errors=20?= =?UTF-8?q?=E2=80=94=20relative=20links=20and=20markdown-link-first?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 63fa7dda392..14352b1bb82 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -18,9 +18,9 @@ This ERC defines two minimal abstract interfaces for on-chain AI inference proof - `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point - `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use -`IProofVerifier` is designed as the Solidity interface layer for OCP ([Observation Commitment Protocol](https://github.com/damonzwicker/observation-commitment-protocol)) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. +`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. -This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](https://github.com/ethereum/ERCs/pull/1748) for on-chain proof commitment. +This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](./erc-8263.md) for on-chain proof commitment. ## Motivation @@ -38,11 +38,11 @@ Verification infrastructure already exists, but it is highly fragmented. **ERCs**: A growing set of ERCs explicitly need on-chain inference verification, but none define a common interface for it: -- **ERC-8183** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined +- **[ERC-8183](./erc-8183.md)** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined - **ERC-8004** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface - **ERC-8263** (AI Proof Commitment) — defines the write path for anchoring proof commitments on-chain, but does not define a corresponding read/verify interface -- **ERC-7992** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered -- **ERC-7007** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier +- **[ERC-7992](./erc-7992.md)** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered +- **[ERC-7007](./erc-7007.md)** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier The problem: these two sides cannot talk to each other. Every protocol that needs verified AI inference today must write a separate adapter per proof system — resulting in vendor lock-in and N×M integration complexity. What's missing is a standard verifier interface that sits in the middle. This ERC provides exactly that: @@ -139,7 +139,7 @@ function supportsInterface(bytes4 interfaceId) ### OCP as the Unifying Primitive -All `IProofVerifier` implementations MUST be designed in accordance with OCP (Observation Commitment Protocol, [damonzwicker/observation-commitment-protocol](https://github.com/damonzwicker/observation-commitment-protocol)). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: +All `IProofVerifier` implementations MUST be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: ``` recompute → compare → confirm inclusion @@ -166,7 +166,7 @@ This is achieved by the four parameters of `verify()`, each with a distinct role - **`inputHash`** — a `bytes32` commitment to the model input. The hash scheme (SHA-256, keccak256, or other) is backend-specific and SHOULD be documented by each implementation. - **`outputHash`** — a `bytes32` commitment to the model output. Hash scheme is backend-specific and SHOULD be documented by each implementation. - **`metadata`** — backend-specific semantic context: model identifier, agent ID, manifest hash, version, registry reference, or any other fields needed to identify *what* was verified. The encoding of `metadata` is backend-specific and SHOULD be documented by each implementation. -- **`proof`** — backend-specific cryptographic material: the ZK proof, EIP-712 signature, TEE attestation report, or multisig aggregate — the data needed to *confirm* the verification claim. +- **`proof`** — backend-specific cryptographic material: the ZK proof, [EIP-712](./eip-712.md) signature, TEE attestation report, or multisig aggregate — the data needed to *confirm* the verification claim. This separation allows tooling and consumers to inspect semantic context (via `metadata`) without needing to parse proof-system-specific cryptographic formats (in `proof`). It also means a single deployed `IProofVerifier` instance can serve as a verifier for multiple models or agents without redeployment. @@ -182,7 +182,7 @@ This separation allows tooling and consumers to inspect semantic context (via `m On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. -This gap is addressed by [WYRIWE](https://github.com/TMerlini/wyriwe) (What You Read Is What Executed). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. +This gap is addressed by WYRIWE (What You Read Is What Executed, TMerlini/wyriwe). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. From 2f0d6a8f789fff149e4e700da58d7fbfa3a5f168 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Thu, 28 May 2026 19:13:57 +0800 Subject: [PATCH 17/40] =?UTF-8?q?erc-8274:=20major=20revision=20=E2=80=94?= =?UTF-8?q?=20rewrite=20abstract/motivation,=20add=20reference=20implement?= =?UTF-8?q?ations=20(SP1=20zkML,=20multisig/oracle),=20add=20ERC-8183/ERC-?= =?UTF-8?q?8004=20composition=20examples,=20revise=20rationale=20and=20sec?= =?UTF-8?q?urity=20considerations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 261 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 233 insertions(+), 28 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 14352b1bb82..1fd97588b99 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -13,14 +13,13 @@ requires: 165 ## Abstract -This ERC defines two minimal abstract interfaces for on-chain AI inference proof verification: +On-chain AI inference can be verified through multiple proof paradigms — zkML, opML, TEE, oracle, multisig, and others — but no common interface exists between them. Every protocol that needs verified AI inference today must write a separate adapter per proof system, resulting in N×M integration complexity and vendor lock-in. -- `IProofVerifier` — the interface that proof backends implement to expose a uniform `verify()` entry point -- `IVerificationMethod` — the interface that consuming contracts implement to declare which verifier they use +This ERC defines two minimal abstract interfaces that sit in the middle: -`IProofVerifier` is designed as the Solidity interface layer for OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol) compatible backends. Each backend implements OCP's core verification primitive — `recompute → compare → confirm inclusion` — for a specific proof system (zkML, opML, TEE, oracle, multisig, etc.), and exposes that implementation through a single uniform `verify()` call. +- `IProofVerifier` — implemented by proof backends, exposing a uniform `verify(inputHash, outputHash, metadata, proof)` entry point across all proof systems +- `IVerificationMethod` — implemented by consuming contracts to declare which verifier they use -This standard composes with [ERC-8004](./erc-8004.md) for agent identity and [ERC-8263](./erc-8263.md) for on-chain proof commitment. ## Motivation @@ -39,8 +38,8 @@ Verification infrastructure already exists, but it is highly fragmented. **ERCs**: A growing set of ERCs explicitly need on-chain inference verification, but none define a common interface for it: - **[ERC-8183](./erc-8183.md)** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined -- **ERC-8004** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface -- **ERC-8263** (AI Proof Commitment) — defines the write path for anchoring proof commitments on-chain, but does not define a corresponding read/verify interface +- **[ERC-8004](./erc-8004.md)** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface +- **[ERC-8001](./erc-8001.md)** (Agent Coordination) — routes multi-agent task results through opaque `executionData` bytes with no inference verification module - **[ERC-7992](./erc-7992.md)** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered - **[ERC-7007](./erc-7007.md)** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier @@ -51,7 +50,7 @@ Verification Backends This ERC ERCs zkML ─┐ ╔══════════════════╗ ┌─ ERC-8183 (Agentic Commerce) opML ─┤ ║ AI Inference ║ ├─ ERC-8004 (Trustless Agents) - TEE ─┼─►║ Proof ║◄─┼─ ERC-8263 (AI Proof Commitment) + TEE ─┼─►║ Proof ║◄─┼─ ERC-8001 (Agent Coordination) Oracle ─┤ ║ Verification ║ ├─ ERC-7992 (Verifiable ML) Multisig / AVS ─┘ ║ Interfaces ║ └─ ERC-7007 (AIGC Token) ╚══════════════════╝ @@ -63,6 +62,8 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S ### IProofVerifier +Proof backends MUST implement `IProofVerifier` and expose `verify()` as a uniform stateless entry point across all proof systems: + ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -85,23 +86,27 @@ interface IProofVerifier { bytes calldata proof ) external view returns (bool); - /// @notice Collision-resistant profile identifier for this backend. - /// MUST equal keccak256(abi.encodePacked(name(), version())) - function proofProfile() external view returns (bytes32); - /// @notice Human-readable proof system name. /// RECOMMENDED format: "{system}/{variant}" - /// Examples: "zkml/risc0", "opml/optimistic", "tee/nitro", "oracle/attestation" + /// Examples: "zkml/sp1", "opml/optimistic", "tee/nitro", "oracle/attestation" function name() external view returns (string memory); /// @notice Proof system version string. /// Examples: "1", "2", "1.0.0" function version() external view returns (string memory); + + /// @notice Collision-resistant profile identifier for this backend. + /// SHOULD equal keccak256(abi.encodePacked(name(), version())) for standard backends. + /// Implementations MAY include additional backend-specific factors (e.g. a circuit + /// commitment hash) for finer-grained collision resistance. + function proofProfile() external view returns (bytes32); } ``` ### IVerificationMethod +Consuming contracts MUST implement `IVerificationMethod` to declare which verifier they use and emit `VerifierUpdated` on any change: + ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -139,7 +144,7 @@ function supportsInterface(bytes4 interfaceId) ### OCP as the Unifying Primitive -All `IProofVerifier` implementations MUST be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: +All `IProofVerifier` implementations SHOULD be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: ``` recompute → compare → confirm inclusion @@ -186,11 +191,13 @@ This gap is addressed by WYRIWE (What You Read Is What Executed, TMerlini/wyriwe Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. -### Relationship to ERC-8263 +### On-Chain Proof Anchoring -ERC-8263 defines the write path: an agent anchors a proof commitment on-chain via `anchor(agentIdScheme, agentId, proofHash)`. This ERC defines the read path: a consumer verifies that commitment via `verify(inputHash, outputHash, metadata, proof)`. +`IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." -The `inputHash` parameter in `verify()` corresponds to the `proofHash` used in the ERC-8263 `anchor()` call for the same inference event. Both commit to the model input as presented to the proof system. The hash scheme (SHA-256, keccak256, or other) is determined by the backend and SHOULD be consistent between the `anchor()` and `verify()` calls. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. +This gap is addressed by ERC-8263 (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. + +These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. This ERC does not prescribe whether a proof is anchored on-chain, or how the `proofHash` in an ERC-8263 anchor relates to the `inputHash` and `outputHash` passed to `verify()`. ## Backwards Compatibility @@ -198,29 +205,227 @@ No backwards compatibility issues. This ERC introduces new interfaces and does n ## Reference Implementation -> To be contributed. Anticipated implementations: -> - zkML backend (RISC Zero / Bonsai) -> - opML optimistic backend -> - TEE backend (AWS Nitro / Intel TDX) -> - Oracle / multisig backend +### zkML Backend (SP1) + +The following implements `IProofVerifier` for SP1 zkVM (Succinct Labs). `programVKey` and `publicValues` are passed together via `metadata`; the verifier decodes both and delegates to the SP1 Plonk circuit. The circuit-specific verification step is noted in comments but omitted from the listing. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title SP1InferenceVerifier +/// @notice IProofVerifier implementation for SP1 zkVM AI inference proofs. +/// +/// metadata: abi.encode(bytes32 programVKey, bytes publicValues) +/// programVKey — SP1 verification key identifying the AI model program +/// publicValues — public outputs committed inside the ZK circuit +/// proof: SP1 proof bytes +contract SP1InferenceVerifier is IProofVerifier { + + bytes32 private constant VERIFIER_HASH = + 0x1b34fe11a637737f0c75c88241669dcf9ca3c03713659265b8241f398a2d286d; + + function verify( + bytes32 inputHash, + bytes32 outputHash, + bytes calldata metadata, + bytes calldata proof + ) external view returns (bool) { + (bytes32 programVKey, bytes memory publicValues) = + abi.decode(metadata, (bytes32, bytes)); + + // Verify that the model identified by programVKey produced outputHash from inputHash, + // using inputHash, outputHash, publicValues and proof as inputs to the circuit verification logic. + return true; + } + + function name() public pure returns (string memory) { + return "zkml/sp1"; + } + + function version() public pure returns (string memory) { + return "1"; + } + + function proofProfile() external pure returns (bytes32) { + // Includes VERIFIER_HASH to distinguish deployments across SP1 verifier versions. + return keccak256(abi.encodePacked(name(), version(), VERIFIER_HASH)); + } + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; + } +} +``` + +### Multisig / Oracle Backend + +The following implements `IProofVerifier` for the multisig / oracle paradigm, derived from TMerlini's BountySettlement proof-of-concept (https://gist.github.com/TMerlini/bf3abd30c332cccb257d0e5bdff1ff95). The off-chain gateway signs an EIP-712 `InferenceAttestation` over `(inputHash, outputHash, registry, timestamp)`; `metadata` carries the attestation context and `proof` carries the concatenated 65-byte signatures. The verifier counts how many registered signers produced valid signatures and passes when the count reaches `THRESHOLD`. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IProofVerifier.sol"; + +/// @title MultisigInferenceVerifier +/// @notice IProofVerifier implementation for multisig-attested AI inference. +/// +/// metadata: abi.encode(address registry, uint64 timestamp) +/// registry — signer registry / EIP-712 verifying contract address +/// timestamp — attestation timestamp for freshness checks +/// proof: concatenated EIP-712 signatures, each 65 bytes (r ++ s ++ v), +/// at least THRESHOLD valid signatures from the registered signer set required +contract MultisigInferenceVerifier is IProofVerifier { + + bytes32 private constant DOMAIN_TYPEHASH = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + + bytes32 private constant ATTESTATION_TYPEHASH = keccak256( + "InferenceAttestation(bytes32 inputHash,bytes32 outputHash,address registry,uint64 timestamp)" + ); + + address[] public signers; + uint256 public immutable THRESHOLD; + + constructor(address[] memory _signers, uint256 _threshold) { + signers = _signers; + THRESHOLD = _threshold; + } + + function verify( + bytes32 inputHash, + bytes32 outputHash, + bytes calldata metadata, + bytes calldata proof + ) external view returns (bool) { + (address registry, uint64 timestamp) = abi.decode(metadata, (address, uint64)); + + bytes32 domainSeparator = keccak256(abi.encode( + DOMAIN_TYPEHASH, + keccak256("KYA-L4"), + keccak256("1"), + block.chainid, + registry + )); + + bytes32 structHash = keccak256(abi.encode( + ATTESTATION_TYPEHASH, + inputHash, + outputHash, + registry, + timestamp + )); + + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + // Split proof into 65-byte chunks, recover each signer, and count + // how many belong to the registered signer set. + uint256 validCount = 0; + uint256 sigCount = proof.length / 65; + for (uint256 i = 0; i < sigCount; i++) { + bytes calldata sig = proof[i * 65:(i + 1) * 65]; + address signer = ecrecover(digest, uint8(sig[64]), bytes32(sig[:32]), bytes32(sig[32:64])); + for (uint256 j = 0; j < signers.length; j++) { + if (signers[j] == signer) { validCount++; break; } + } + } + return validCount >= THRESHOLD; + } + + function name() public pure returns (string memory) { + return "multisig/eip712"; + } + + function version() public pure returns (string memory) { + return "1"; + } + + function proofProfile() external pure returns (bytes32) { + return keccak256(abi.encodePacked(name(), version())); + } + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IProofVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; + } +} +``` + +Anticipated additional backends: opML optimistic, TEE (AWS Nitro / Intel TDX). + +### Composition with ERC-8183 + +ERC-8183 defines an AgenticCommerce contract where the evaluator calls `complete(jobId, reason, optParams)` or `reject(jobId, reason, optParams)` after assessing a provider's submission. An evaluator contract implements `IVerificationMethod` to declare its verifier, and gates the `complete()` call on a passing `verify()` result: + +```solidity +interface IAgenticCommerce { + function complete(uint256 jobId, bytes32 reason, bytes calldata optParams) external; + function reject(uint256 jobId, bytes32 reason, bytes calldata optParams) external; +} + +contract ProofEvaluator is IVerificationMethod { + IProofVerifier private _verifier; + IAgenticCommerce public immutable ACP; + + event VerifierUpdated(address indexed previousVerifier, address indexed newVerifier); + + function getVerifier() external view returns (IProofVerifier) { + return _verifier; + } + + function settle( + uint256 jobId, + bytes32 inputHash, + bytes32 outputHash, + bytes calldata metadata, + bytes calldata proof + ) external { + if (_verifier.verify(inputHash, outputHash, metadata, proof)) { + ACP.complete(jobId, outputHash, ""); + } else { + ACP.reject(jobId, outputHash, ""); + } + } +} +``` + +### Composition with ERC-8004 + +ERC-8004 assigns each agent a `uint256 agentId` (an ERC-721 tokenId) and exposes `getAgentWallet(uint256 agentId)` on the Identity Registry to resolve the agent's current wallet address. A consuming contract can tie a verified proof back to an on-chain agent identity by decoding `agentId` from `metadata` and querying the registry: + +```solidity +interface IErc8004IdentityRegistry { + function getAgentWallet(uint256 agentId) external view returns (address); +} + +// agentId in metadata may be encoded as bytes32(uint256(erc8004AgentId)) +// per the ERC-8263 agentIdScheme = 0x01 (REGISTRY) convention +uint256 agentId = uint256(abi.decode(metadata, (bytes32))); +address agentWallet = IErc8004IdentityRegistry(identityRegistry).getAgentWallet(agentId); +``` ## Security Considerations -**Input trustworthiness** +**Input and output trustworthiness** -`verify()` confirms that a proof is valid for a given `inputHash`. It does not confirm that the input itself was trustworthy or correctly derived. Input sanitisation and provenance are the responsibility of the layer above. Consumers that require input provenance guarantees SHOULD verify the input hash independently before accepting a proof. +`verify()` confirms that a proof is cryptographically valid for the given `inputHash` and `outputHash`. It does not confirm that the input was correctly derived or that the output is semantically correct for the intended task. A manipulated input can produce a valid proof over a misleading output. Consumers MUST NOT treat a passing `verify()` as a guarantee of correctness beyond what the proof system itself covers. **Opaque proof bytes** Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. -**Verifier mutability** +**Replay protection** -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. +`IProofVerifier` does not define replay protection. For oracle and multisig backends, a valid signature over `(inputHash, outputHash)` may be replayed across chains or contracts if the backend's signing domain does not bind to a specific chain ID, contract address, or nonce. Each `IProofVerifier` implementation MUST document its replay protection guarantees. Consumers SHOULD verify that the `metadata` fields (e.g. timestamp, registry address) are fresh and scoped to the expected context before accepting a proof. -**No liveness guarantee** +**Verifier mutability** -`verify()` is a `view` function. It provides no guarantee that the underlying proof system is live or that the model referred to by `inputHash` is available. +`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. ## Copyright From 1a0d7965b226ca369cc5e2c55f2d592c1482b392 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Fri, 29 May 2026 10:06:02 +0800 Subject: [PATCH 18/40] erc-8274: apply community feedback (OCP language, WYRIWE links, proof anchoring clarification) --- ERCS/erc-8274.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 1fd97588b99..51d71fd5d77 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -144,23 +144,19 @@ function supportsInterface(bytes4 interfaceId) ### OCP as the Unifying Primitive -All `IProofVerifier` implementations SHOULD be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP's core design principle is that verification should not be locked to any specific blockchain, contract interface, or proof system — any independent party SHOULD be able to verify a commitment using only the publicly available on-chain record, without calling a specific contract or depending on any particular infrastructure. OCP derives its core verification primitive from this principle: +All `IProofVerifier` implementations SHOULD be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP defines the minimum verification primitive that any proof system must satisfy: ``` recompute → compare → confirm inclusion ``` -The current five verification paradigms all satisfy this primitive, each with a different trust model: +A verifier satisfying OCP: -| Paradigm | How OCP primitive is satisfied | -|----------|-------------------------------| -| zkML | Recomputes via ZK circuit; comparison and inclusion confirmed by on-chain proof verifier | -| opML | Recomputes via replay; comparison confirmed after challenge window closes | -| TEE | Recomputes inside enclave; comparison and inclusion confirmed by attestation report | -| Oracle | Recomputes off-chain; comparison and inclusion confirmed by attested signature | -| Multisig / AVS | Recomputes across independent nodes; comparison confirmed by threshold aggregate | +- Deterministically recomputes a digest from the claimed observation +- Compares it against the committed digest +- Confirms the commitment is present in the on-chain record -As new proof paradigms emerge in the future, they are expected to satisfy the same OCP primitive and implement `IProofVerifier` accordingly. Any verification approach that cannot be expressed in terms of `recompute → compare → confirm inclusion` is out of scope for this interface. +Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. ### Stateless Verifier Design @@ -187,7 +183,7 @@ This separation allows tooling and consumers to inspect semantic context (via `m On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. -This gap is addressed by WYRIWE (What You Read Is What Executed, TMerlini/wyriwe). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. +This gap is addressed by WYRIWE (What You Read Is What Executed, [ERC draft](https://github.com/TMerlini/wyriwe/blob/main/ERC-draft.md), [discussion](https://ethereum-magicians.org/t/wyriwe-what-you-read-is-what-you-execute-input-provenance-for-verifiable-ai-inference/28655)). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. @@ -197,7 +193,7 @@ Consumers that require input provenance guarantees are RECOMMENDED to adopt the This gap is addressed by ERC-8263 (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. -These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. This ERC does not prescribe whether a proof is anchored on-chain, or how the `proofHash` in an ERC-8263 anchor relates to the `inputHash` and `outputHash` passed to `verify()`. +These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain via ERC-8263 for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. ## Backwards Compatibility From 61d925fee216f6360266b0838d964b681f29078b Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Fri, 29 May 2026 10:34:40 +0800 Subject: [PATCH 19/40] erc-8274: fix CI lint errors and add co-author Damonzwicker --- ERCS/erc-8274.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 51d71fd5d77..ff6a21e00b0 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -2,7 +2,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends -author: JimmyShi22 (@JimmyShi22) +author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track @@ -183,7 +183,7 @@ This separation allows tooling and consumers to inspect semantic context (via `m On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. -This gap is addressed by WYRIWE (What You Read Is What Executed, [ERC draft](https://github.com/TMerlini/wyriwe/blob/main/ERC-draft.md), [discussion](https://ethereum-magicians.org/t/wyriwe-what-you-read-is-what-you-execute-input-provenance-for-verifiable-ai-inference/28655)). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. +This gap is addressed by WYRIWE (What You Read Is What Executed, ERC draft, [discussion](https://ethereum-magicians.org/t/wyriwe-what-you-read-is-what-you-execute-input-provenance-for-verifiable-ai-inference/28655)). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. @@ -191,7 +191,7 @@ Consumers that require input provenance guarantees are RECOMMENDED to adopt the `IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." -This gap is addressed by ERC-8263 (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. +This gap is addressed by [ERC-8263](./erc-8263.md) (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain via ERC-8263 for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. @@ -259,7 +259,7 @@ contract SP1InferenceVerifier is IProofVerifier { ### Multisig / Oracle Backend -The following implements `IProofVerifier` for the multisig / oracle paradigm, derived from TMerlini's BountySettlement proof-of-concept (https://gist.github.com/TMerlini/bf3abd30c332cccb257d0e5bdff1ff95). The off-chain gateway signs an EIP-712 `InferenceAttestation` over `(inputHash, outputHash, registry, timestamp)`; `metadata` carries the attestation context and `proof` carries the concatenated 65-byte signatures. The verifier counts how many registered signers produced valid signatures and passes when the count reaches `THRESHOLD`. +The following implements `IProofVerifier` for the multisig / oracle paradigm, derived from TMerlini's BountySettlement proof-of-concept. The off-chain gateway signs an EIP-712 `InferenceAttestation` over `(inputHash, outputHash, registry, timestamp)`; `metadata` carries the attestation context and `proof` carries the concatenated 65-byte signatures. The verifier counts how many registered signers produced valid signatures and passes when the count reaches `THRESHOLD`. ```solidity // SPDX-License-Identifier: MIT From 6017635c6d627746d4d0f0742d0c5711c8e86c34 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Fri, 29 May 2026 11:11:25 +0800 Subject: [PATCH 20/40] erc-8274: fix CI errors (link format erc->eip, remove external URL, link ERC-721) --- ERCS/erc-8274.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index ff6a21e00b0..a97c315b136 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -37,11 +37,11 @@ Verification infrastructure already exists, but it is highly fragmented. **ERCs**: A growing set of ERCs explicitly need on-chain inference verification, but none define a common interface for it: -- **[ERC-8183](./erc-8183.md)** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined -- **[ERC-8004](./erc-8004.md)** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface -- **[ERC-8001](./erc-8001.md)** (Agent Coordination) — routes multi-agent task results through opaque `executionData` bytes with no inference verification module -- **[ERC-7992](./erc-7992.md)** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered -- **[ERC-7007](./erc-7007.md)** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier +- **[ERC-8183](./eip-8183.md)** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined +- **[ERC-8004](./eip-8004.md)** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface +- **[ERC-8001](./eip-8001.md)** (Agent Coordination) — routes multi-agent task results through opaque `executionData` bytes with no inference verification module +- **[ERC-7992](./eip-7992.md)** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered +- **[ERC-7007](./eip-7007.md)** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier The problem: these two sides cannot talk to each other. Every protocol that needs verified AI inference today must write a separate adapter per proof system — resulting in vendor lock-in and N×M integration complexity. What's missing is a standard verifier interface that sits in the middle. This ERC provides exactly that: @@ -129,7 +129,7 @@ interface IVerificationMethod { ### Interface Detection -Implementations SHOULD support [ERC-165](./erc-165.md): +Implementations SHOULD support [ERC-165](./eip-165.md): ```solidity function supportsInterface(bytes4 interfaceId) @@ -183,7 +183,7 @@ This separation allows tooling and consumers to inspect semantic context (via `m On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. -This gap is addressed by WYRIWE (What You Read Is What Executed, ERC draft, [discussion](https://ethereum-magicians.org/t/wyriwe-what-you-read-is-what-you-execute-input-provenance-for-verifiable-ai-inference/28655)). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. +This gap is addressed by WYRIWE (What You Read Is What Executed, ERC draft, discussion). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. @@ -191,7 +191,7 @@ Consumers that require input provenance guarantees are RECOMMENDED to adopt the `IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." -This gap is addressed by [ERC-8263](./erc-8263.md) (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. +This gap is addressed by [ERC-8263](./eip-8263.md) (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain via ERC-8263 for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. @@ -392,7 +392,7 @@ contract ProofEvaluator is IVerificationMethod { ### Composition with ERC-8004 -ERC-8004 assigns each agent a `uint256 agentId` (an ERC-721 tokenId) and exposes `getAgentWallet(uint256 agentId)` on the Identity Registry to resolve the agent's current wallet address. A consuming contract can tie a verified proof back to an on-chain agent identity by decoding `agentId` from `metadata` and querying the registry: +ERC-8004 assigns each agent a `uint256 agentId` (an [ERC-721](./eip-721.md) tokenId) and exposes `getAgentWallet(uint256 agentId)` on the Identity Registry to resolve the agent's current wallet address. A consuming contract can tie a verified proof back to an on-chain agent identity by decoding `agentId` from `metadata` and querying the registry: ```solidity interface IErc8004IdentityRegistry { From b37acd777d1972d26a7f104ad84de20c86b653b7 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Fri, 29 May 2026 11:26:08 +0800 Subject: [PATCH 21/40] erc-8274: remove ERC-8263 relative link pending PR #1748 merge --- ERCS/erc-8274.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index a97c315b136..dac2d179eef 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -191,7 +191,7 @@ Consumers that require input provenance guarantees are RECOMMENDED to adopt the `IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." -This gap is addressed by [ERC-8263](./eip-8263.md) (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. +This gap is addressed by ERC-8263 (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain via ERC-8263 for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. From 4de0100d40c5d773c8dae70fa9ff7aee74620b8e Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Fri, 29 May 2026 14:30:09 +0800 Subject: [PATCH 22/40] erc-8274: fix markdown-link-first CI error, restructure Rationale headings - Remove ERC-8263 number pattern from On-Chain Proof Anchoring section to resolve eipw markdown-link-first conflict with HTMLProofer (ERC-8263 PR #1748 not yet merged; cross-reference deferred to v0.2) - Rename Rationale subsections to Primitive/Design/Query/Result pattern for symmetric coverage framing --- ERCS/erc-8274.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index dac2d179eef..bf68e9c5fdf 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -142,7 +142,7 @@ function supportsInterface(bytes4 interfaceId) ## Rationale -### OCP as the Unifying Primitive +### Primitive: OCP as the Unifying Model All `IProofVerifier` implementations SHOULD be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP defines the minimum verification primitive that any proof system must satisfy: @@ -158,7 +158,7 @@ A verifier satisfying OCP: Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. -### Stateless Verifier Design +### Design: Stateless Verifier `IProofVerifier` is designed as a stateless interface: the verifier contract holds no state about which model, agent, or session is being verified. All context necessary for verification is passed in through the function parameters. @@ -179,7 +179,7 @@ This separation allows tooling and consumers to inspect semantic context (via `m - **Oracle / attestation**: submission deadline, signer registry address, agent identifier - **Multisig / AVS**: quorum identifier, signing epoch, validator set commitment -### Input Provenance +### Query: Input Provenance On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. @@ -187,13 +187,13 @@ This gap is addressed by WYRIWE (What You Read Is What Executed, ERC draft, disc Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. -### On-Chain Proof Anchoring +### Result: Proof Anchoring `IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." -This gap is addressed by ERC-8263 (Onchain Proof Layer for AI Agents). ERC-8263 defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the ERC-8263 anchor alongside the cryptographic check via `verify()`. +This gap is addressed by a companion on-chain proof anchoring standard (Onchain Proof Layer for AI Agents). That standard defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the on-chain anchor alongside the cryptographic check via `verify()`. -These two ERCs are complementary: ERC-8263 is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain via ERC-8263 for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. +The two standards are complementary: the anchoring layer is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain by the anchoring layer for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. ## Backwards Compatibility From 1f7d8e58a635202428e3ca69ee82ea144d339f27 Mon Sep 17 00:00:00 2001 From: JimmyShi22 <417711026@qq.com> Date: Thu, 4 Jun 2026 22:02:27 +0800 Subject: [PATCH 23/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Tiago=20Merlini=20(@?= =?UTF-8?q?Echo-Merlini)=20=E4=B8=BA=E5=85=B1=E5=90=8C=E4=BD=9C=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index bf68e9c5fdf..52ac6f1098c 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -2,7 +2,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends -author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker) +author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track From 2ce9945b0a4595d67ac0659e511ae4eb24ad78f3 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 00:11:10 +0800 Subject: [PATCH 24/40] =?UTF-8?q?docs:=20update=20ERC-8274=20to=20v0.2=20?= =?UTF-8?q?=E2=80=94=20two-layer=20architecture=20(IProofVerifier=20+=20IA?= =?UTF-8?q?gentVerifier)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 604 +++++++++++++++++++++++++++++------------------ 1 file changed, 379 insertions(+), 225 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 52ac6f1098c..27701ab42a5 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -1,111 +1,150 @@ --- eip: 8274 title: AI Inference Proof Verification Interfaces -description: Minimal abstract interfaces for on-chain AI inference proof verification across OCP-compatible backends +description: A two-layer interface standard for on-chain AI inference verification, separating agent-level authorization (IAgentVerifier) from proof-system-level cryptographic verification (IProofVerifier) author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track category: ERC created: 2026-05-26 -requires: 165 +requires: 165, 712 --- ## Abstract On-chain AI inference can be verified through multiple proof paradigms — zkML, opML, TEE, oracle, multisig, and others — but no common interface exists between them. Every protocol that needs verified AI inference today must write a separate adapter per proof system, resulting in N×M integration complexity and vendor lock-in. -This ERC defines two minimal abstract interfaces that sit in the middle: +This ERC defines three minimal abstract interfaces organized into two layers: -- `IProofVerifier` — implemented by proof backends, exposing a uniform `verify(inputHash, outputHash, metadata, proof)` entry point across all proof systems -- `IVerificationMethod` — implemented by consuming contracts to declare which verifier they use +- **`IProofVerifier`** — the inner algorithm layer, implemented by proof system providers (ZK teams, TEE vendors, oracle networks). Stateless. Answers: "is this proof cryptographically valid for this input and output?" +- **`IAgentVerifier`** — the outer application layer, implemented by application developers. Stateful. Wraps an `IProofVerifier`. Answers: "for this task, was this agent authorized to make this claim, and does the proof confirm it?" +- **`IAgentVerifiable`** — implemented by settlement contracts to declare which `IAgentVerifier` they use. +The separation allows proof system providers and application developers to work independently: neither needs to know the other's internals. ## Motivation Verification infrastructure already exists, but it is highly fragmented. -**Verification Projects**: On-chain AI verification is already live across five paradigms: +**Verification paradigms already live:** -| Paradigm | Description | -|----------|-------------| -| zkML | Cryptographic proof that a specific model produced a given output from a given input | -| opML | Optimistic AI inference execution with a challenge window for fraud proofs | -| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | -| Oracle | Off-chain AI inference result attested by a trusted signer network | -| Multisig / AVS | AI inference result confirmed by a threshold of independent validators | +| Paradigm | Description | +| ----------- | ---------------------------------------------------------------------------------------- | +| zkML | Cryptographic proof that a specific model produced a given output from a given input | +| opML | Optimistic AI inference execution with a challenge window for fraud proofs | +| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | +| Attestation | Off-chain inference result certified by one or more authorized signers — covers oracle gateways (e.g. Chainlink), multisig / AVS validator networks (e.g. EigenLayer), and judgment validators | -**ERCs**: A growing set of ERCs explicitly need on-chain inference verification, but none define a common interface for it: +**ERCs that need inference verification:** - **[ERC-8183](./eip-8183.md)** (Agentic Commerce) — evaluator "may verify a ZK proof" before releasing payment, but no verifier interface is defined - **[ERC-8004](./eip-8004.md)** (Trustless Agents) — Validation Registry lists zkML/TEE verifiers as examples, but specifies no contract interface - **[ERC-8001](./eip-8001.md)** (Agent Coordination) — routes multi-agent task results through opaque `executionData` bytes with no inference verification module -- **[ERC-7992](./eip-7992.md)** (Verifiable ML) — defines a registry for ZK proofs only, leaving opML, TEE, Oracle, and Multisig uncovered - **[ERC-7007](./eip-7007.md)** (Verifiable AIGC Token) — accepts opaque `bytes proof` with no model identifier or proof-system identifier The problem: these two sides cannot talk to each other. Every protocol that needs verified AI inference today must write a separate adapter per proof system — resulting in vendor lock-in and N×M integration complexity. What's missing is a standard verifier interface that sits in the middle. This ERC provides exactly that: ``` -Verification Backends This ERC ERCs - - zkML ─┐ ╔══════════════════╗ ┌─ ERC-8183 (Agentic Commerce) - opML ─┤ ║ AI Inference ║ ├─ ERC-8004 (Trustless Agents) - TEE ─┼─►║ Proof ║◄─┼─ ERC-8001 (Agent Coordination) - Oracle ─┤ ║ Verification ║ ├─ ERC-7992 (Verifiable ML) - Multisig / AVS ─┘ ║ Interfaces ║ └─ ERC-7007 (AIGC Token) - ╚══════════════════╝ +Verification Backends This ERC ERCs + + ╔══════════════════╗ + zkML ─┐ ║ AI Inference ║ ┌─ ERC-8183 (Agentic Commerce) + opML ─┤ ║ Proof ║ ├─ ERC-8004 (Trustless Agents) + TEE ─┼─►║ Verification ║◄─┼─ ERC-8001 (Agent Coordination) + Attestation ─┘ ║ Interfaces ║ └─ ERC-7007 (AIGC Token) + ╚══════════════════╝ ``` ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### IProofVerifier +--- + +### IProofVerifier — Inner Algorithm Layer + +`IProofVerifier` is the inner algorithm layer. Three defining properties: -Proof backends MUST implement `IProofVerifier` and expose `verify()` as a uniform stateless entry point across all proof systems: +- **Stateless** — holds no configuration about which agent, model, or session is being verified; all context is passed through parameters on every call +- **Verification algorithm specific** — encapsulates the cryptographic verification logic of one proof system (ZK, TEE, optimistic, or attestation) +- **Implemented by proof system providers** — the parties who implement cryptographic verification for a specific proof system (e.g. ZK teams, TEE vendors, oracle networks, attestation gateway operators); called by agent developers from within `IAgentVerifier`, with no knowledge of the agent context above ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IProofVerifier -/// @notice Interface for AI inference proof verification backends. -/// Each implementation executes the OCP verification primitive -/// (recompute → compare → confirm inclusion) for a specific proof system. +/// @notice Stateless cryptographic verification interface for AI inference proof backends. +/// Implemented by proof system providers independently of any calling context. +/// Answers: "is this proof cryptographically valid for this input and output?" interface IProofVerifier { /// @notice Verify an AI inference proof. - /// @param inputHash Commitment to the model input (e.g. SHA-256 or keccak256 digest). Hash scheme is backend-specific and SHOULD be documented by each implementation. - /// @param outputHash Commitment to the model output. Hash scheme is backend-specific and SHOULD be documented by each implementation. - /// @param metadata Backend-specific context (e.g. model identifier, agent ID, manifest hash, version) - /// @param proof Backend-specific cryptographic proof bytes (e.g. ZK proof, EIP-712 signature, TEE attestation) - /// @return True if the proof is valid for the given input and output + /// @param inputHash Commitment to the model input (hash scheme is backend-specific). + /// @param outputHash Commitment to the model output (hash scheme is backend-specific). + /// @param metadata Invariant deployment configuration — fields stable across calls + /// for this verifier deployment (e.g. ZK circuit key, TEE enclave hash, + /// signer registry address). Stored by IAgentVerifier; callers never + /// encode or see this field. + /// @param proof Per-inference cryptographic evidence (e.g. ZK proof bytes, + /// EIP-712 signature, TEE attestation report). + /// @return True if the proof is cryptographically valid for the given input and output. function verify( bytes32 inputHash, bytes32 outputHash, bytes calldata metadata, bytes calldata proof - ) external view returns (bool); + ) external returns (bool); - /// @notice Human-readable proof system name. - /// RECOMMENDED format: "{system}/{variant}" - /// Examples: "zkml/sp1", "opml/optimistic", "tee/nitro", "oracle/attestation" - function name() external view returns (string memory); + /// @notice Proof system identifier in "{paradigm}/{variant}" format. + function proofSystem() external view returns (string memory); - /// @notice Proof system version string. - /// Examples: "1", "2", "1.0.0" - function version() external view returns (string memory); - - /// @notice Collision-resistant profile identifier for this backend. - /// SHOULD equal keccak256(abi.encodePacked(name(), version())) for standard backends. - /// Implementations MAY include additional backend-specific factors (e.g. a circuit - /// commitment hash) for finer-grained collision resistance. + /// @notice Collision-resistant identifier for this specific deployment. + /// SHOULD equal keccak256(abi.encodePacked(proofSystem(), deploymentSalt)) where + /// deploymentSalt is a backend-specific constant (e.g. circuit commitment hash, + /// enclave measurement). function proofProfile() external view returns (bytes32); } ``` -### IVerificationMethod +#### `verify()` + +`verify()` takes four parameters with distinct roles: + +- **`inputHash`** — commitment to the model input. The hash scheme is backend-specific and MUST be documented by each implementation. +- **`outputHash`** — commitment to the model output. Hash scheme is backend-specific. +- **`metadata`** — invariant configuration that does not change between calls for a given deployment: ZK circuit verification key, TEE enclave hash, signer registry address, etc. This is deployment-time configuration owned by `IAgentVerifier`; the settlement contract never encodes or sees it. +- **`proof`** — per-inference cryptographic evidence specific to this inference event: ZK proof bytes, EIP-712 signature, TEE attestation report, or multisig aggregate. + +#### `proofSystem()` + +Identifies what kind of proof system this verifier implements. Returns a `{paradigm}/{variant}` string: + +- **`paradigm`** — the verification paradigm, determining the trust model and security assumptions (see table below) +- **`variant`** — the specific implementation within that paradigm -Consuming contracts MUST implement `IVerificationMethod` to declare which verifier they use and emit `VerifierUpdated` on any change: +| Paradigm | Trust model | Security assumptions | `proofSystem()` examples | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `zk` | Mathematical: ZK circuit proves a specific model produced a given output from a given input | Soundness of the ZK proving system and correctness of the circuit | `zk/sp1`, `zk/ezkl` | +| `op` | Economic: execution is assumed correct within a challenge window; fraud proofs slash the submitter | At least one honest challenger is watching within the challenge window | `op/ora` | +| `tee` | Hardware: a trusted enclave attests that execution occurred in an isolated environment | Trustworthiness of the hardware manufacturer; no side-channel or supply-chain compromise | `tee/nitro`, `tee/marlin` | +| `attestation` | Authoritative: one or more authorized signers certify the result — covers oracle gateways, multisig validator networks, and judgment validators | Authorized signer set is not compromised; accountability is reputational or stake-based depending on the variant | `attestation/multisig`, `attestation/wyriwe`, `attestation/judgment` | + +#### `proofProfile()` + +Returns a collision-resistant `bytes32` identifier for this specific verifier deployment. Where `proofSystem()` identifies the proof system type, `proofProfile()` identifies the exact deployment — allowing consumers to distinguish between, for example, two `zk/sp1` verifiers compiled against different circuit versions, or two `tee/nitro` verifiers with different enclave measurements. + +`proofProfile()` is included in `verificationDigest`: the same inputs verified by different proof system deployments will produce different digests, making the audit trail unambiguous. + +--- + +### IAgentVerifier — Outer Application Layer + +`IAgentVerifier` is the outer application layer. Three defining properties: + +- **Stateful** — stores deployment-time configuration: which `IProofVerifier`(s) to use, agent authorization rules, `metadata` to pass to the inner verifier, and optionally task tracking state +- **Application layer** — orchestrates agent-specific authorization and verification logic; shields settlement contracts from proof-system differences so callers invoke the same `verify()` interface regardless of whether the backend is ZK, TEE, or attestation +- **Implemented by agent developers** — the parties who deploy verification services for their agents, configuring authorization rules and `IProofVerifier` backends; called by settlement protocols (e.g. ERC-8183, ERC-8275) via `IAgentVerifiable`, with the cryptographic internals remaining the exclusive concern of proof system providers ```solidity // SPDX-License-Identifier: MIT @@ -113,97 +152,258 @@ pragma solidity ^0.8.0; import "./IProofVerifier.sol"; -/// @title IVerificationMethod -/// @notice Interface for contracts that declare which proof verifier they use. -interface IVerificationMethod { - /// @notice Returns the proof verifier used by this contract. - function getVerifier() external view returns (IProofVerifier); +/// @title IAgentVerifier +/// @notice Stateful application-layer verification interface. +/// Implemented by application developers. Wraps one or more IProofVerifier(s). +/// Answers: "for this task, was this agent authorized to make this claim, +/// and does the proof confirm it?" +interface IAgentVerifier { + /// @notice SHOULD be emitted on every verify() call — both passing and failing. + /// Carries the raw preimage fields of verificationDigest, enabling any observer + /// to independently recompute the digest and confirm inclusion per OCP + /// (recompute → compare → confirm). + event VerificationCompleted( + bytes32 indexed taskId, + bytes32 indexed agentId, + bytes32 indexed verificationDigest, + bool valid, + bytes32 inputHash, + bytes32 outputHash, + bytes32 agentProofProfile // fingerprint of the verification logic used for this event + ); + + /// @notice Verify an agent's inference claim for a specific task. + /// @param taskId Task identifier. Binds verification to a single task. + /// Callers SHOULD encode uint256 IDs as bytes32 + /// (e.g. ERC-8183 jobId, ERC-8275 periodId). + /// @param agentId Identity of the agent that performed the inference. + /// Checked against the implementation's stored authorization config. + /// @param inputHash Commitment to the model input. + /// @param outputHash Commitment to the model output. + /// @param proof Cryptographic evidence, passed unchanged to the inner IProofVerifier(s). + /// @return valid Whether the agent is authorized and the proof is valid. + /// @return verificationDigest Digest fingerprinting this verification event, computed from + /// taskId, agentId, inputHash, outputHash, valid, and agentProofProfile. + /// Returned regardless of outcome. MAY be used as an on-chain + /// audit anchor (e.g. ERC-8183 job.reason). + /// @dev NOT view — implementations MAY write state (e.g. single-use taskId tracking). + function verify( + bytes32 taskId, + bytes32 agentId, + bytes32 inputHash, + bytes32 outputHash, + bytes calldata proof + ) external returns (bool valid, bytes32 verificationDigest); + +} +``` + +#### Stateful Design + +`IAgentVerifier` is stateful by design. Its state falls into two categories: + +**Application state** — deployment-time application rules specific to the agent. What to store here is left to the implementation; typical examples include agent authorization configuration (allowlist, registry reference, on-chain role), task state for single-use enforcement, model or policy requirements, and accepted time windows. + +**`IProofVerifier` reference(s) and `metadata`** — which proof backend(s) to call and the invariant `metadata` to pass each one. Typical examples include a single `IProofVerifier` address with its corresponding circuit key or enclave hash encoded as `metadata`, or a keyed mapping of verifiers for multi-paradigm deployments. Both are set at deployment and SHOULD be immutable; `metadata` encoding is specific to each `IProofVerifier` and opaque to callers above. - /// @notice MUST be emitted when the verifier address changes. - event VerifierUpdated( +This ERC does not mandate the internal structure of `IAgentVerifier` implementations. Implementations MAY use a single `IProofVerifier`, an array, a mapping, or any other arrangement. The only normative requirement is the `verify()` signature above. + +#### Verification Commitment + +`verify()` returns `(bool valid, bytes32 verificationDigest)`. The `verificationDigest` is a commitment to the full verification event, computed from: + +``` +keccak256(abi.encode(taskId, agentId, inputHash, outputHash, valid, agentProofProfile)) +``` + +Including `valid` and `agentProofProfile` ensures that the same inputs verified by different proof systems, or with different outcomes, produce different digests. + +`VerificationCompleted` SHOULD be emitted on every call — passing and failing — carrying the same fields as the preimage. This follows OCP's commitment model: any external observer can independently verify a `VerificationCompleted` record by applying the recompute → compare → confirm inclusion procedure, without calling any contract and trusting any intermediary. + +`verificationDigest` MAY be stored as an on-chain audit anchor by the settlement contract (e.g. as ERC-8183's `job.reason`). + +--- + +### IAgentVerifiable — Declaration Layer + +Settlement contracts MUST implement `IAgentVerifiable` to declare which `IAgentVerifier` they use and MUST emit `AgentVerifierUpdated` on any change. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IAgentVerifier.sol"; + +/// @title IAgentVerifiable +/// @notice Interface for settlement contracts that declare which agent verifier they use. +interface IAgentVerifiable { + /// @notice Returns the agent verifier used by this contract. + function getAgentVerifier() external view returns (IAgentVerifier); + + /// @notice MUST be emitted when the agent verifier address changes. + event AgentVerifierUpdated( address indexed previousVerifier, address indexed newVerifier ); } ``` +--- + ### Interface Detection -Implementations SHOULD support [ERC-165](./eip-165.md): +All implementations SHOULD support [ERC-165](./eip-165.md): ```solidity -function supportsInterface(bytes4 interfaceId) - external view returns (bool) -{ +// IProofVerifier +function supportsInterface(bytes4 interfaceId) external view returns (bool) { return interfaceId == type(IProofVerifier).interfaceId || interfaceId == type(IERC165).interfaceId; } + +// IAgentVerifier +function supportsInterface(bytes4 interfaceId) external view returns (bool) { + return interfaceId == type(IAgentVerifier).interfaceId + || interfaceId == type(IERC165).interfaceId; +} ``` +--- + ## Rationale ### Primitive: OCP as the Unifying Model -All `IProofVerifier` implementations SHOULD be designed in accordance with OCP (Observation Commitment Protocol, damonzwicker/observation-commitment-protocol). OCP defines the minimum verification primitive that any proof system must satisfy: +OCP (Observation Commitment Protocol, ERC-8281) is a system-agnostic verification primitive: given the emitted event data, any observer can independently verify a commitment without trusting the system that produced it or relying on any contract. It defines the minimum procedure any proof system must satisfy: ``` recompute → compare → confirm inclusion ``` -A verifier satisfying OCP: +This ERC adopts OCP as the unifying model for `IAgentVerifier` events — not only because every proof backend satisfies the primitive, but because `VerificationCompleted` maps directly onto it: the event is the observation, `verificationDigest` is the commitment, and the emitted fields are the preimage. -- Deterministically recomputes a digest from the claimed observation -- Compares it against the committed digest -- Confirms the commitment is present in the on-chain record +`verificationDigest` is computed from `(taskId, agentId, inputHash, outputHash, valid, agentProofProfile)`. The event carries those same fields alongside the digest, making every record self-describing and independently auditable: -Each `IProofVerifier` implementation executes this primitive for a specific proof system. `proofProfile()` identifies which OCP-compatible proof system the implementation uses. +- **On-chain**: recompute the digest from held parameters and compare against what was emitted +- **Off-chain**: apply all three steps — recompute from emitted fields, compare, confirm event inclusion -### Design: Stateless Verifier +`confirm inclusion` requires reading event logs, which is off-chain only. `IProofVerifier.verify()` handles the first two steps on-chain; external observers handle the third via `VerificationCompleted` records. The same primitive thus covers both contexts without requiring contracts to fetch their own logs. -`IProofVerifier` is designed as a stateless interface: the verifier contract holds no state about which model, agent, or session is being verified. All context necessary for verification is passed in through the function parameters. +`agentProofProfile` in the digest ensures that the same inputs verified by different deployments produce different digests. -This is achieved by the four parameters of `verify()`, each with a distinct role: +### Design: Two-Layer Architecture -- **`inputHash`** — a `bytes32` commitment to the model input. The hash scheme (SHA-256, keccak256, or other) is backend-specific and SHOULD be documented by each implementation. -- **`outputHash`** — a `bytes32` commitment to the model output. Hash scheme is backend-specific and SHOULD be documented by each implementation. -- **`metadata`** — backend-specific semantic context: model identifier, agent ID, manifest hash, version, registry reference, or any other fields needed to identify *what* was verified. The encoding of `metadata` is backend-specific and SHOULD be documented by each implementation. -- **`proof`** — backend-specific cryptographic material: the ZK proof, [EIP-712](./eip-712.md) signature, TEE attestation report, or multisig aggregate — the data needed to *confirm* the verification claim. +The split between `IAgentVerifier` (outer application layer) and `IProofVerifier` (inner algorithm layer) exists because two independent parties must implement the standard: -This separation allows tooling and consumers to inspect semantic context (via `metadata`) without needing to parse proof-system-specific cryptographic formats (in `proof`). It also means a single deployed `IProofVerifier` instance can serve as a verifier for multiple models or agents without redeployment. +- **Proof system providers** implement `IProofVerifier`. They know their cryptographic details but not the calling application context. `IProofVerifier` is **stateless** — one deployed instance serves many `IAgentVerifier` deployments without redeployment; `metadata` carries all invariant configuration and is owned by `IAgentVerifier`. +- **Agent developers** implement `IAgentVerifier`. They know their application rules but should not be coupled to a specific proof system. `IAgentVerifier` is **stateful** — authorization rules, model requirements, and task tracking belong in state. -`metadata` is typed as `bytes calldata` rather than `bytes32` deliberately. A `bytes32` hash supports equality checks but cannot support ordering comparisons (`>`, `<`, `>=`). Verifier implementations commonly need to decode individual fields from `metadata` for ordering logic — for example, comparing timestamps for freshness bounds, checking nonces for replay prevention, or enforcing minimum version requirements. Each `IProofVerifier` implementation SHOULD document its expected `metadata` encoding. Typical fields by paradigm: +Settlement contracts MUST NOT call `IProofVerifier` directly — doing so would require knowing the backend's `metadata` encoding. The two-layer boundary keeps each party isolated: -- **zkML**: circuit identifier, model commitment, circuit version -- **opML**: request identifier, challenge deadline, submitter address -- **TEE**: enclave identifier, PCR values, validity deadline -- **Oracle / attestation**: submission deadline, signer registry address, agent identifier -- **Multisig / AVS**: quorum identifier, signing epoch, validator set commitment +``` +IAgentVerifier.verify(taskId, agentId, inputHash, outputHash, proof) + → check taskId (if single-use) + → check agentId authorization (if needed) + → delegate to IProofVerifier(s) internally + → compute verificationDigest + → return (valid, verificationDigest) +``` + +**Opacity.** The two-layer design achieves opacity at every level: + +- Settlement contracts are **opaque to the proof backend** — they call `IAgentVerifier.verify()` the same way regardless of whether the backend is ZK, TEE, or attestation. +- `IAgentVerifier` is **opaque to the settlement contract** — its internal verifier configuration, `metadata` encoding, and authorization rules are not exposed to callers. ### Query: Input Provenance -On-chain AI agents typically construct their inputs by reading from external sources — ENS records, NFT metadata, oracle feeds, or contract return values — and applying preprocessing rules before the data is passed to the model. This means `inputHash` alone carries no trustworthiness guarantee — it is a commitment to whatever input was provided, but says nothing about where that input came from or how it was derived. A verifier confirms "this model produced this output from this input" but cannot confirm whether the input itself was legitimate. +`inputHash` commits to whatever input was provided but says nothing about its origin. A verifier confirms "this model produced this output from this input" — not whether the input was legitimate. -This gap is addressed by WYRIWE (What You Read Is What Executed, ERC draft, discussion). WYRIWE extends the single `inputHash` into a three-commitment scheme covering the raw input, the sanitization pipeline applied to it, and the sanitized input that was actually executed — allowing an independent verifier to confirm that the input passed to the model is derived from a known source through a known, committed pipeline. `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` field — same key, same keccak256 construction. +WYRIWE (ERC-8299) fills this gap with a three-commitment scheme: -Consumers that require input provenance guarantees are RECOMMENDED to adopt the WYRIWE approach alongside `verify()`. This ERC does not prescribe how `inputHash` was derived. +``` +rawInputHash = keccak256(raw_user_input) +sanitizationPipelineHash = keccak256(sanitization_spec_cid || rawInputHash) +inputHash = keccak256(sanitized_input) +``` + +`IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` — same field, same construction. `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. + +Consumers requiring input provenance SHOULD adopt WYRIWE alongside `verify()`. This ERC does not prescribe how `inputHash` is derived. ### Result: Proof Anchoring -`IProofVerifier` is stateless by design: the verifier contract holds no record of past calls, and each `verify()` invocation is independent and ephemeral. `verify()` confirms that a proof is cryptographically valid for a given `inputHash` and `outputHash`, but says nothing about when the proof was generated — a consumer can confirm "this proof checks out" but cannot confirm "the agent committed to this proof before any result was acted upon." +`verify()` confirms cryptographic validity but not *when* the proof was generated. A consumer can confirm "this proof checks out" but not "the proof was committed before any action was taken." + +ERC-8263 fills this gap: agents anchor a `proofHash` on-chain at inference time via `anchor(agentIdScheme, agentId, proofHash)`. Consumers requiring proof binding SHOULD verify the anchor alongside `verify()`. + +The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in ERC-8263's `AttestationIndex`. + +| | Purpose | +|--|---------| +| `proofHash` | "This proof was committed at time T" | +| `verificationDigest` | "This verification event occurred with these parameters" | + +--- + +## Interoperability + +### ERC-8183 — Agentic Commerce + +ERC-8183 defines a job lifecycle where an evaluator calls `complete()` or `reject()` after assessing a submission. Four decisions apply directly: + +**`complete()` signature.** The evaluator implements `IAgentVerifiable`; the verifier is resolved at settlement via `getAgentVerifier()` — no pre-registration required. The caller supplies only agent-level claims: + +```solidity +complete(jobId, agentId, inputHash, outputHash, proof) +``` + +`metadata` and the verifier address are owned by `IAgentVerifier` internally. + +**`job.reason` = `verificationDigest`.** ERC-8183's `bytes32 reason` field is the natural anchor for `verificationDigest` — computed from all context, unique per event, and OCP-verifiable by any observer. + +**`verify()` returns `bool`.** No reconstruction needed: + +```solidity +(bool valid, bytes32 verificationDigest) = + getAgentVerifier().verify(bytes32(jobId), agentId, inputHash, outputHash, proof); + +if (valid) ACP.complete(jobId, verificationDigest, ""); +else ACP.reject(jobId, verificationDigest, ""); +``` + +**`inputHash` follows WYRIWE** — `keccak256(sanitized_input)`, binding verification to the full provenance chain. + +### WYRIWE — Input Provenance + +WYRIWE (ERC-8299) defines a triple-hash scheme for input provenance: + +``` +rawInputHash = keccak256(raw_user_input) +sanitizationPipelineHash = keccak256(sanitization_spec_cid || rawInputHash) +inputHash = keccak256(sanitized_input) +``` + +**Layer separation.** WYRIWE is L3 (input provenance); this ERC is L4 (verification). They compose vertically and are independent. -This gap is addressed by a companion on-chain proof anchoring standard (Onchain Proof Layer for AI Agents). That standard defines the write path: an agent anchors a `proofHash` on-chain via `anchor(agentIdScheme, agentId, proofHash)` at the time of inference, creating an immutable, timestamped on-chain commitment. Consumers that require proof binding — confirming that the proof was anchored before a downstream action was taken — are RECOMMENDED to verify the on-chain anchor alongside the cryptographic check via `verify()`. +**`inputHash` alignment.** `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` — same field, same construction. -The two standards are complementary: the anchoring layer is the commitment layer, this ERC is the verification layer. For OCP-compatible backends using the SHA-256 proof profile, `inputHash` is the same digest as the `proofHash` committed on-chain by the anchoring layer for the same inference event. The specific hash function is profile-declared; implementations using other hash functions SHOULD declare their proof profile accordingly. +**Ready-made backend.** `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. + +--- ## Backwards Compatibility No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. +--- + ## Reference Implementation -### zkML Backend (SP1) +The following three examples form a complete composable stack. Each layer is independently deployable; Layer 2 wraps Layer 1 and Layer 3 wraps Layer 2. -The following implements `IProofVerifier` for SP1 zkVM (Succinct Labs). `programVKey` and `publicValues` are passed together via `metadata`; the verifier decodes both and delegates to the SP1 Plonk circuit. The circuit-specific verification step is noted in comments but omitted from the listing. +### Layer 1 — IProofVerifier: Proof System Backend + +`SP1ProofVerifier` implements the ZK paradigm. `proofSystem()` is declared `public` so `proofProfile()` can call it internally. ```solidity // SPDX-License-Identifier: MIT @@ -211,14 +411,13 @@ pragma solidity ^0.8.0; import "./IProofVerifier.sol"; -/// @title SP1InferenceVerifier +/// @title SP1ProofVerifier /// @notice IProofVerifier implementation for SP1 zkVM AI inference proofs. /// -/// metadata: abi.encode(bytes32 programVKey, bytes publicValues) -/// programVKey — SP1 verification key identifying the AI model program -/// publicValues — public outputs committed inside the ZK circuit -/// proof: SP1 proof bytes -contract SP1InferenceVerifier is IProofVerifier { +/// metadata: abi.encode(bytes32 programVKey) +/// programVKey — SP1 verification key identifying the ZK circuit for this model +/// proof: SP1 proof bytes (Plonk or Groth16 format) +contract SP1ProofVerifier is IProofVerifier { bytes32 private constant VERIFIER_HASH = 0x1b34fe11a637737f0c75c88241669dcf9ca3c03713659265b8241f398a2d286d; @@ -228,200 +427,155 @@ contract SP1InferenceVerifier is IProofVerifier { bytes32 outputHash, bytes calldata metadata, bytes calldata proof - ) external view returns (bool) { - (bytes32 programVKey, bytes memory publicValues) = - abi.decode(metadata, (bytes32, bytes)); - - // Verify that the model identified by programVKey produced outputHash from inputHash, - // using inputHash, outputHash, publicValues and proof as inputs to the circuit verification logic. + ) external returns (bool) { + bytes32 programVKey = abi.decode(metadata, (bytes32)); + // Verify the SP1 ZK proof: circuit identified by programVKey produced + // outputHash from inputHash. Delegates to SP1 Plonk verifier contract. + // Full implementation omitted; see SP1 documentation. return true; } - function name() public pure returns (string memory) { - return "zkml/sp1"; - } - - function version() public pure returns (string memory) { - return "1"; + function proofSystem() public pure returns (string memory) { + return "zk/sp1"; } function proofProfile() external pure returns (bytes32) { - // Includes VERIFIER_HASH to distinguish deployments across SP1 verifier versions. - return keccak256(abi.encodePacked(name(), version(), VERIFIER_HASH)); - } - - function supportsInterface(bytes4 interfaceId) external pure returns (bool) { - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; + return keccak256(abi.encodePacked(proofSystem(), VERIFIER_HASH)); } } ``` -### Multisig / Oracle Backend +### Layer 2 — IAgentVerifier: Wraps IProofVerifier -The following implements `IProofVerifier` for the multisig / oracle paradigm, derived from TMerlini's BountySettlement proof-of-concept. The off-chain gateway signs an EIP-712 `InferenceAttestation` over `(inputHash, outputHash, registry, timestamp)`; `metadata` carries the attestation context and `proof` carries the concatenated 65-byte signatures. The verifier counts how many registered signers produced valid signatures and passes when the count reaches `THRESHOLD`. +`AgentVerifier` is constructed with an `IProofVerifier` instance (e.g. `SP1ProofVerifier` from Layer 1), deployment `metadata`, and an authorized agent set. The inner verifier configuration is held in contract state — the settlement contract in Layer 3 never sees `metadata` or the verifier address. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import "./IAgentVerifier.sol"; import "./IProofVerifier.sol"; -/// @title MultisigInferenceVerifier -/// @notice IProofVerifier implementation for multisig-attested AI inference. +/// @title AgentVerifier +/// @notice IAgentVerifier implementation wrapping a single IProofVerifier backend. /// -/// metadata: abi.encode(address registry, uint64 timestamp) -/// registry — signer registry / EIP-712 verifying contract address -/// timestamp — attestation timestamp for freshness checks -/// proof: concatenated EIP-712 signatures, each 65 bytes (r ++ s ++ v), -/// at least THRESHOLD valid signatures from the registered signer set required -contract MultisigInferenceVerifier is IProofVerifier { - - bytes32 private constant DOMAIN_TYPEHASH = keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ); - - bytes32 private constant ATTESTATION_TYPEHASH = keccak256( - "InferenceAttestation(bytes32 inputHash,bytes32 outputHash,address registry,uint64 timestamp)" - ); - - address[] public signers; - uint256 public immutable THRESHOLD; - - constructor(address[] memory _signers, uint256 _threshold) { - signers = _signers; - THRESHOLD = _threshold; +/// metadata is stored at deployment and passed to the inner verifier on every call. +contract AgentVerifier is IAgentVerifier { + + IProofVerifier private immutable _verifier; + bytes private _metadata; + + mapping(bytes32 => bool) private _authorizedAgents; + mapping(bytes32 => bool) private _usedTasks; + + constructor( + IProofVerifier verifier_, + bytes memory metadata_, + bytes32[] memory authorizedAgents_ + ) { + _verifier = verifier_; + _metadata = metadata_; + for (uint256 i = 0; i < authorizedAgents_.length; i++) { + _authorizedAgents[authorizedAgents_[i]] = true; + } } function verify( + bytes32 taskId, + bytes32 agentId, bytes32 inputHash, bytes32 outputHash, - bytes calldata metadata, bytes calldata proof - ) external view returns (bool) { - (address registry, uint64 timestamp) = abi.decode(metadata, (address, uint64)); - - bytes32 domainSeparator = keccak256(abi.encode( - DOMAIN_TYPEHASH, - keccak256("KYA-L4"), - keccak256("1"), - block.chainid, - registry - )); - - bytes32 structHash = keccak256(abi.encode( - ATTESTATION_TYPEHASH, - inputHash, - outputHash, - registry, - timestamp - )); - - bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); - - // Split proof into 65-byte chunks, recover each signer, and count - // how many belong to the registered signer set. - uint256 validCount = 0; - uint256 sigCount = proof.length / 65; - for (uint256 i = 0; i < sigCount; i++) { - bytes calldata sig = proof[i * 65:(i + 1) * 65]; - address signer = ecrecover(digest, uint8(sig[64]), bytes32(sig[:32]), bytes32(sig[32:64])); - for (uint256 j = 0; j < signers.length; j++) { - if (signers[j] == signer) { validCount++; break; } - } + ) external returns (bool valid, bytes32 verificationDigest) { + if (!_usedTasks[taskId] && _authorizedAgents[agentId]) { + valid = _verifier.verify(inputHash, outputHash, _metadata, proof); + if (valid) _usedTasks[taskId] = true; } - return validCount >= THRESHOLD; - } - - function name() public pure returns (string memory) { - return "multisig/eip712"; - } - function version() public pure returns (string memory) { - return "1"; - } - - function proofProfile() external pure returns (bytes32) { - return keccak256(abi.encodePacked(name(), version())); - } + bytes32 agentProofProfile = _verifier.proofProfile(); + verificationDigest = keccak256(abi.encode( + taskId, agentId, inputHash, outputHash, valid, agentProofProfile + )); - function supportsInterface(bytes4 interfaceId) external pure returns (bool) { - return interfaceId == type(IProofVerifier).interfaceId - || interfaceId == type(IERC165).interfaceId; + emit VerificationCompleted( + taskId, agentId, verificationDigest, valid, inputHash, outputHash, agentProofProfile + ); } } ``` -Anticipated additional backends: opML optimistic, TEE (AWS Nitro / Intel TDX). +### Layer 3 — Settlement Contract (ERC-8183): Wraps IAgentVerifier -### Composition with ERC-8183 - -ERC-8183 defines an AgenticCommerce contract where the evaluator calls `complete(jobId, reason, optParams)` or `reject(jobId, reason, optParams)` after assessing a provider's submission. An evaluator contract implements `IVerificationMethod` to declare its verifier, and gates the `complete()` call on a passing `verify()` result: +`ProofEvaluator` implements `IAgentVerifiable`, declares its `IAgentVerifier` via `getAgentVerifier()`, and calls `verify()` at settlement time. `verificationDigest` is forwarded as `job.reason` to the ERC-8183 ACP protocol. ```solidity -interface IAgenticCommerce { - function complete(uint256 jobId, bytes32 reason, bytes calldata optParams) external; - function reject(uint256 jobId, bytes32 reason, bytes calldata optParams) external; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IAgentVerifiable.sol"; +import "./IAgentVerifier.sol"; + +interface IACP { + function complete(uint256 jobId, bytes32 reason, bytes calldata data) external; + function reject(uint256 jobId, bytes32 reason, bytes calldata data) external; } -contract ProofEvaluator is IVerificationMethod { - IProofVerifier private _verifier; - IAgenticCommerce public immutable ACP; +contract ProofEvaluator is IAgentVerifiable { + IAgentVerifier private _agentVerifier; + IACP private immutable _acp; - event VerifierUpdated(address indexed previousVerifier, address indexed newVerifier); + constructor(IAgentVerifier agentVerifier_, IACP acp_) { + _agentVerifier = agentVerifier_; + _acp = acp_; + emit AgentVerifierUpdated(address(0), address(agentVerifier_)); + } - function getVerifier() external view returns (IProofVerifier) { - return _verifier; + function getAgentVerifier() external view returns (IAgentVerifier) { + return _agentVerifier; } function settle( uint256 jobId, + bytes32 agentId, bytes32 inputHash, bytes32 outputHash, - bytes calldata metadata, bytes calldata proof ) external { - if (_verifier.verify(inputHash, outputHash, metadata, proof)) { - ACP.complete(jobId, outputHash, ""); - } else { - ACP.reject(jobId, outputHash, ""); - } + bytes32 taskId = bytes32(jobId); + (bool valid, bytes32 verificationDigest) = + _agentVerifier.verify(taskId, agentId, inputHash, outputHash, proof); + + if (valid) _acp.complete(jobId, verificationDigest, ""); + else _acp.reject(jobId, verificationDigest, ""); } } ``` -### Composition with ERC-8004 - -ERC-8004 assigns each agent a `uint256 agentId` (an [ERC-721](./eip-721.md) tokenId) and exposes `getAgentWallet(uint256 agentId)` on the Identity Registry to resolve the agent's current wallet address. A consuming contract can tie a verified proof back to an on-chain agent identity by decoding `agentId` from `metadata` and querying the registry: - -```solidity -interface IErc8004IdentityRegistry { - function getAgentWallet(uint256 agentId) external view returns (address); -} - -// agentId in metadata may be encoded as bytes32(uint256(erc8004AgentId)) -// per the ERC-8263 agentIdScheme = 0x01 (REGISTRY) convention -uint256 agentId = uint256(abi.decode(metadata, (bytes32))); -address agentWallet = IErc8004IdentityRegistry(identityRegistry).getAgentWallet(agentId); -``` +--- ## Security Considerations -**Input and output trustworthiness** +**IProofVerifier trust boundary** + +This ERC defines the interface but does not vet `IProofVerifier` implementations. Agent developers MUST NOT assume a given `IProofVerifier` is secure simply because it satisfies the interface. Before configuring a backend, agent developers SHOULD independently assess its cryptographic assumptions, audit status, and known attack surface. A backend that always returns `true`, uses a broken circuit, or accepts replayed attestations will silently undermine the entire verification chain. -`verify()` confirms that a proof is cryptographically valid for the given `inputHash` and `outputHash`. It does not confirm that the input was correctly derived or that the output is semantically correct for the intended task. A manipulated input can produce a valid proof over a misleading output. Consumers MUST NOT treat a passing `verify()` as a guarantee of correctness beyond what the proof system itself covers. +**Trust chain** -**Opaque proof bytes** +``` +settlement contract → IAgentVerifier → IProofVerifier[] +``` -Consumers MUST NOT assume structural compatibility of `proof` bytes across different `IProofVerifier` implementations. Passing proof bytes from one backend to a different backend's verifier MUST NOT be treated as safe. +Each link SHOULD be audited independently. The same trust boundary applies at every layer: settlement contracts MUST NOT assume a given `IAgentVerifier` is secure simply because it satisfies the interface, just as agent developers MUST NOT assume the same of `IProofVerifier`. `IAgentVerifier` does not expose its internal verifier set; consumers requiring auditability SHOULD verify the full deployment configuration at setup time. **Replay protection** -`IProofVerifier` does not define replay protection. For oracle and multisig backends, a valid signature over `(inputHash, outputHash)` may be replayed across chains or contracts if the backend's signing domain does not bind to a specific chain ID, contract address, or nonce. Each `IProofVerifier` implementation MUST document its replay protection guarantees. Consumers SHOULD verify that the `metadata` fields (e.g. timestamp, registry address) are fresh and scoped to the expected context before accepting a proof. +`IProofVerifier` does not define replay protection. A valid proof over `(inputHash, outputHash)` may replay across contexts if the underlying proof system does not bind to a chain ID, contract address, or nonce. Replay protection, if required, SHOULD be implemented in `IAgentVerifier`. -**Verifier mutability** +**Verification commitment self-containment** -`getVerifier()` MAY return different addresses over time. High-value consumers SHOULD monitor `VerifierUpdated` events and treat verifier changes as security-relevant configuration changes. +`VerificationCompleted` is designed to be independently verifiable without querying any contract state. On-chain state is mutable — contracts may be upgraded, storage may change, and authorization rules may evolve. If reconstructing or confirming a `verificationDigest` required reading live contract state, historical records would become unverifiable as that state changed. The event carries all preimage fields alongside the digest precisely so that any observer can verify a past event against the immutable log alone, independent of current contract state. + +--- ## Copyright From 90048a5f3280244be875c5ce34591ef1bc5603fe Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 00:17:10 +0800 Subject: [PATCH 25/40] docs: rename Design section to Architecture: Two Composable, Opaque Layers --- ERCS/erc-8274.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 27701ab42a5..346ac5e5a2b 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -291,7 +291,7 @@ This ERC adopts OCP as the unifying model for `IAgentVerifier` events — not on `agentProofProfile` in the digest ensures that the same inputs verified by different deployments produce different digests. -### Design: Two-Layer Architecture +### Architecture: Two Composable, Opaque Layers The split between `IAgentVerifier` (outer application layer) and `IProofVerifier` (inner algorithm layer) exists because two independent parties must implement the standard: From 810ac52a34d0cd9d87d443e2caf8101b367f6aaa Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 00:25:06 +0800 Subject: [PATCH 26/40] docs: rename Interoperability to Composability in Practice --- ERCS/erc-8274.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 346ac5e5a2b..7f18dcdefe8 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -345,7 +345,7 @@ The anchor check is an application-layer concern — it belongs in `IAgentVerifi --- -## Interoperability +## Composability in Practice ### ERC-8183 — Agentic Commerce From 6958c6d72a49e5f67df4ceb5bb2e4ebfbdc92744 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 00:44:41 +0800 Subject: [PATCH 27/40] =?UTF-8?q?fix:=20CI=20failures=20=E2=80=94=20descri?= =?UTF-8?q?ption,=20ERC=20links,=20Composability=20section=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shorten description to ≤140 chars and remove forbidden word 'standard' - Add markdown links for first occurrences of ERC-8281, ERC-8299, ERC-8263 - Move 'Composability in Practice' inside Reference Implementation - Rename original Reference Implementation content to 'Coding in Practice' - Demote Layer 1/2/3 from ### to #### --- ERCS/erc-8274.md | 106 +++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 7f18dcdefe8..b341b1623c3 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -1,7 +1,7 @@ --- eip: 8274 title: AI Inference Proof Verification Interfaces -description: A two-layer interface standard for on-chain AI inference verification, separating agent-level authorization (IAgentVerifier) from proof-system-level cryptographic verification (IProofVerifier) +description: Two-layer interface for on-chain AI inference proof verification, separating IAgentVerifier (application) from IProofVerifier (algorithm) author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft @@ -274,7 +274,7 @@ function supportsInterface(bytes4 interfaceId) external view returns (bool) { ### Primitive: OCP as the Unifying Model -OCP (Observation Commitment Protocol, ERC-8281) is a system-agnostic verification primitive: given the emitted event data, any observer can independently verify a commitment without trusting the system that produced it or relying on any contract. It defines the minimum procedure any proof system must satisfy: +OCP (Observation Commitment Protocol, [ERC-8281](./eip-8281.md)) is a system-agnostic verification primitive: given the emitted event data, any observer can independently verify a commitment without trusting the system that produced it or relying on any contract. It defines the minimum procedure any proof system must satisfy: ``` recompute → compare → confirm inclusion @@ -318,7 +318,7 @@ IAgentVerifier.verify(taskId, agentId, inputHash, outputHash, proof) `inputHash` commits to whatever input was provided but says nothing about its origin. A verifier confirms "this model produced this output from this input" — not whether the input was legitimate. -WYRIWE (ERC-8299) fills this gap with a three-commitment scheme: +WYRIWE ([ERC-8299](./eip-8299.md)) fills this gap with a three-commitment scheme: ``` rawInputHash = keccak256(raw_user_input) @@ -334,7 +334,7 @@ Consumers requiring input provenance SHOULD adopt WYRIWE alongside `verify()`. T `verify()` confirms cryptographic validity but not *when* the proof was generated. A consumer can confirm "this proof checks out" but not "the proof was committed before any action was taken." -ERC-8263 fills this gap: agents anchor a `proofHash` on-chain at inference time via `anchor(agentIdScheme, agentId, proofHash)`. Consumers requiring proof binding SHOULD verify the anchor alongside `verify()`. +[ERC-8263](./eip-8263.md) fills this gap: agents anchor a `proofHash` on-chain at inference time via `anchor(agentIdScheme, agentId, proofHash)`. Consumers requiring proof binding SHOULD verify the anchor alongside `verify()`. The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in ERC-8263's `AttestationIndex`. @@ -345,52 +345,6 @@ The anchor check is an application-layer concern — it belongs in `IAgentVerifi --- -## Composability in Practice - -### ERC-8183 — Agentic Commerce - -ERC-8183 defines a job lifecycle where an evaluator calls `complete()` or `reject()` after assessing a submission. Four decisions apply directly: - -**`complete()` signature.** The evaluator implements `IAgentVerifiable`; the verifier is resolved at settlement via `getAgentVerifier()` — no pre-registration required. The caller supplies only agent-level claims: - -```solidity -complete(jobId, agentId, inputHash, outputHash, proof) -``` - -`metadata` and the verifier address are owned by `IAgentVerifier` internally. - -**`job.reason` = `verificationDigest`.** ERC-8183's `bytes32 reason` field is the natural anchor for `verificationDigest` — computed from all context, unique per event, and OCP-verifiable by any observer. - -**`verify()` returns `bool`.** No reconstruction needed: - -```solidity -(bool valid, bytes32 verificationDigest) = - getAgentVerifier().verify(bytes32(jobId), agentId, inputHash, outputHash, proof); - -if (valid) ACP.complete(jobId, verificationDigest, ""); -else ACP.reject(jobId, verificationDigest, ""); -``` - -**`inputHash` follows WYRIWE** — `keccak256(sanitized_input)`, binding verification to the full provenance chain. - -### WYRIWE — Input Provenance - -WYRIWE (ERC-8299) defines a triple-hash scheme for input provenance: - -``` -rawInputHash = keccak256(raw_user_input) -sanitizationPipelineHash = keccak256(sanitization_spec_cid || rawInputHash) -inputHash = keccak256(sanitized_input) -``` - -**Layer separation.** WYRIWE is L3 (input provenance); this ERC is L4 (verification). They compose vertically and are independent. - -**`inputHash` alignment.** `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` — same field, same construction. - -**Ready-made backend.** `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. - ---- - ## Backwards Compatibility No backwards compatibility issues. This ERC introduces new interfaces and does not modify any existing standard. @@ -399,9 +353,11 @@ No backwards compatibility issues. This ERC introduces new interfaces and does n ## Reference Implementation +### Coding in Practice + The following three examples form a complete composable stack. Each layer is independently deployable; Layer 2 wraps Layer 1 and Layer 3 wraps Layer 2. -### Layer 1 — IProofVerifier: Proof System Backend +#### Layer 1 — IProofVerifier: Proof System Backend `SP1ProofVerifier` implements the ZK paradigm. `proofSystem()` is declared `public` so `proofProfile()` can call it internally. @@ -445,7 +401,7 @@ contract SP1ProofVerifier is IProofVerifier { } ``` -### Layer 2 — IAgentVerifier: Wraps IProofVerifier +#### Layer 2 — IAgentVerifier: Wraps IProofVerifier `AgentVerifier` is constructed with an `IProofVerifier` instance (e.g. `SP1ProofVerifier` from Layer 1), deployment `metadata`, and an authorized agent set. The inner verifier configuration is held in contract state — the settlement contract in Layer 3 never sees `metadata` or the verifier address. @@ -504,7 +460,7 @@ contract AgentVerifier is IAgentVerifier { } ``` -### Layer 3 — Settlement Contract (ERC-8183): Wraps IAgentVerifier +#### Layer 3 — Settlement Contract (ERC-8183): Wraps IAgentVerifier `ProofEvaluator` implements `IAgentVerifiable`, declares its `IAgentVerifier` via `getAgentVerifier()`, and calls `verify()` at settlement time. `verificationDigest` is forwarded as `job.reason` to the ERC-8183 ACP protocol. @@ -551,6 +507,50 @@ contract ProofEvaluator is IAgentVerifiable { } ``` +### Composability in Practice + +#### ERC-8183 — Agentic Commerce + +ERC-8183 defines a job lifecycle where an evaluator calls `complete()` or `reject()` after assessing a submission. Four decisions apply directly: + +**`complete()` signature.** The evaluator implements `IAgentVerifiable`; the verifier is resolved at settlement via `getAgentVerifier()` — no pre-registration required. The caller supplies only agent-level claims: + +```solidity +complete(jobId, agentId, inputHash, outputHash, proof) +``` + +`metadata` and the verifier address are owned by `IAgentVerifier` internally. + +**`job.reason` = `verificationDigest`.** ERC-8183's `bytes32 reason` field is the natural anchor for `verificationDigest` — computed from all context, unique per event, and OCP-verifiable by any observer. + +**`verify()` returns `bool`.** No reconstruction needed: + +```solidity +(bool valid, bytes32 verificationDigest) = + getAgentVerifier().verify(bytes32(jobId), agentId, inputHash, outputHash, proof); + +if (valid) ACP.complete(jobId, verificationDigest, ""); +else ACP.reject(jobId, verificationDigest, ""); +``` + +**`inputHash` follows WYRIWE** — `keccak256(sanitized_input)`, binding verification to the full provenance chain. + +#### WYRIWE — Input Provenance + +WYRIWE (ERC-8299) defines a triple-hash scheme for input provenance: + +``` +rawInputHash = keccak256(raw_user_input) +sanitizationPipelineHash = keccak256(sanitization_spec_cid || rawInputHash) +inputHash = keccak256(sanitized_input) +``` + +**Layer separation.** WYRIWE is L3 (input provenance); this ERC is L4 (verification). They compose vertically and are independent. + +**`inputHash` alignment.** `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` — same field, same construction. + +**Ready-made backend.** `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. + --- ## Security Considerations From a7814eae7551a5ce934a1f01fd4b4f6e5bcbbe54 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 00:56:40 +0800 Subject: [PATCH 28/40] =?UTF-8?q?fix:=20resolve=20remaining=20CI=20failure?= =?UTF-8?q?s=20=E2=80=94=20EIP-712=20link,=20remove=20ERC-8275,=20drop=20u?= =?UTF-8?q?nmerged=20ERC=20numbers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add [EIP-712](./eip-712.md) link at first plain-text occurrence (eipw markdown-link-first) - Remove ERC-8275 from bullet point (unmerged, no file to link to) - Replace ERC-8281/8299/8263 references with OCP/WYRIWE/descriptive text (HTMLProofer: files don't exist) --- ERCS/erc-8274.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index b341b1623c3..1ef092e6ff5 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -114,7 +114,7 @@ interface IProofVerifier { - **`inputHash`** — commitment to the model input. The hash scheme is backend-specific and MUST be documented by each implementation. - **`outputHash`** — commitment to the model output. Hash scheme is backend-specific. - **`metadata`** — invariant configuration that does not change between calls for a given deployment: ZK circuit verification key, TEE enclave hash, signer registry address, etc. This is deployment-time configuration owned by `IAgentVerifier`; the settlement contract never encodes or sees it. -- **`proof`** — per-inference cryptographic evidence specific to this inference event: ZK proof bytes, EIP-712 signature, TEE attestation report, or multisig aggregate. +- **`proof`** — per-inference cryptographic evidence specific to this inference event: ZK proof bytes, [EIP-712](./eip-712.md) signature, TEE attestation report, or multisig aggregate. #### `proofSystem()` @@ -144,7 +144,7 @@ Returns a collision-resistant `bytes32` identifier for this specific verifier de - **Stateful** — stores deployment-time configuration: which `IProofVerifier`(s) to use, agent authorization rules, `metadata` to pass to the inner verifier, and optionally task tracking state - **Application layer** — orchestrates agent-specific authorization and verification logic; shields settlement contracts from proof-system differences so callers invoke the same `verify()` interface regardless of whether the backend is ZK, TEE, or attestation -- **Implemented by agent developers** — the parties who deploy verification services for their agents, configuring authorization rules and `IProofVerifier` backends; called by settlement protocols (e.g. ERC-8183, ERC-8275) via `IAgentVerifiable`, with the cryptographic internals remaining the exclusive concern of proof system providers +- **Implemented by agent developers** — the parties who deploy verification services for their agents, configuring authorization rules and `IProofVerifier` backends; called by settlement protocols (e.g. ERC-8183) via `IAgentVerifiable`, with the cryptographic internals remaining the exclusive concern of proof system providers ```solidity // SPDX-License-Identifier: MIT @@ -274,7 +274,7 @@ function supportsInterface(bytes4 interfaceId) external view returns (bool) { ### Primitive: OCP as the Unifying Model -OCP (Observation Commitment Protocol, [ERC-8281](./eip-8281.md)) is a system-agnostic verification primitive: given the emitted event data, any observer can independently verify a commitment without trusting the system that produced it or relying on any contract. It defines the minimum procedure any proof system must satisfy: +OCP (Observation Commitment Protocol) is a system-agnostic verification primitive: given the emitted event data, any observer can independently verify a commitment without trusting the system that produced it or relying on any contract. It defines the minimum procedure any proof system must satisfy: ``` recompute → compare → confirm inclusion @@ -318,7 +318,7 @@ IAgentVerifier.verify(taskId, agentId, inputHash, outputHash, proof) `inputHash` commits to whatever input was provided but says nothing about its origin. A verifier confirms "this model produced this output from this input" — not whether the input was legitimate. -WYRIWE ([ERC-8299](./eip-8299.md)) fills this gap with a three-commitment scheme: +WYRIWE fills this gap with a three-commitment scheme: ``` rawInputHash = keccak256(raw_user_input) @@ -334,9 +334,9 @@ Consumers requiring input provenance SHOULD adopt WYRIWE alongside `verify()`. T `verify()` confirms cryptographic validity but not *when* the proof was generated. A consumer can confirm "this proof checks out" but not "the proof was committed before any action was taken." -[ERC-8263](./eip-8263.md) fills this gap: agents anchor a `proofHash` on-chain at inference time via `anchor(agentIdScheme, agentId, proofHash)`. Consumers requiring proof binding SHOULD verify the anchor alongside `verify()`. +Proof anchoring fills this gap: agents anchor a `proofHash` on-chain at inference time via an anchor registry. Consumers requiring proof binding SHOULD verify the anchor alongside `verify()`. -The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in ERC-8263's `AttestationIndex`. +The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in the anchor registry. | | Purpose | |--|---------| @@ -537,7 +537,7 @@ else ACP.reject(jobId, verificationDigest, ""); #### WYRIWE — Input Provenance -WYRIWE (ERC-8299) defines a triple-hash scheme for input provenance: +WYRIWE defines a triple-hash scheme for input provenance: ``` rawInputHash = keccak256(raw_user_input) From 07139e1698ede7ef3ff1f5ea66aeda7e14ab61b2 Mon Sep 17 00:00:00 2001 From: babyblueviper1 Date: Fri, 12 Jun 2026 14:06:06 -0400 Subject: [PATCH 29/40] erc-8274: add Judgment Validator subsection to Composability in Practice Concrete wiring of the attestation/judgment variant per t/28083 #97-#102: inner-layer verify semantics + verdict encoding, Type A/B deterministic-bool aggregation (derived confidence, outcome-oracle dependency stated explicitly, self-dealing guard), recordPointer accountability invariants, optional WYRIWE L4 execution binding, production reference data. --- ERCS/erc-8274.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 1ef092e6ff5..d178ee144f8 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -551,6 +551,42 @@ inputHash = keccak256(sanitized_input) **Ready-made backend.** `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. +#### Judgment Validator — `attestation/judgment` + +A **judgment claim** asserts that a validator examined a proposed action and issued a verdict on its soundness — in settings where the right answer is not computable at decision time (pre-trade review, contribution-reward evaluation, compliance sign-off). Verification establishes **authenticity, never soundness**: `verify()` answers *"is this authentically the named validator's verdict over exactly this input?"* It MUST NOT be read as *"the action is sound."* + +**Inner-layer wiring.** `proofSystem()` returns `"attestation/judgment"`. `verify()` checks the validator's signature over the canonical payload binding `{verdict object, inputHash, validator identity}`; the scheme is committed by `proofProfile()` (the production reference uses schnorr over a Nostr event). `outputHash` commits to the verdict object: + +```json +{ + "verdict": "approve | approve_with_concerns | reject", + "confidence": 0.85, + "issues": ["", "..."] +} +``` + +Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for judgment claims — absent, not zero-filled. + +**How the deterministic bool emerges.** Judgment is non-deterministic; the interface output is not. Aggregation lives in `IAgentVerifier` (never the inner layer), by claim type: + +- **Type A — outcome-verifiable.** Validator confidence weights are *derived* as a pure function of settled commit-reveal records (verdicts committed on-chain before outcomes, revealed after) — recomputable by any party from chain state, with no updater-trust problem. **Outcome-oracle dependency, stated explicitly:** this recomputation is trustless only where outcomes settle on-chain; off-chain-settled outcomes (an exchange account, a counterparty system) require an outcome oracle, and the aggregation inherits that oracle's trust assumptions. Consumers MUST be able to distinguish on-chain-settled from oracle-attested records. +- **Type B — non-verifiable.** Usage-based weight MUST count distinct counterparties with their own at-stake identity, not call volume, and SHOULD be capped relative to outcome-derived weight (the self-dealing guard). + +The resulting bool gates settlement exactly like any other backend (see the ERC-8183 wiring above): authenticity from the inner layer, threshold over derived weights at the outer. + +**`recordPointer` accountability invariants** (normative for judgment claims; the record format is reference data): + +1. Losses MUST be present — a record showing only wins is marketing, not accountability. +2. Outcomes MUST settle somewhere the validator cannot edit. +3. The pre-outcome timestamp MUST be anchored at issue time to a system the validator does not control (the same primitive as OCP's observation commitment). + +Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`. + +**Execution binding (optional).** Where the judged action is subsequently executed, the reviewed→executed chain of custody binds with the WYRIWE L4 attestation — `JudgmentExecutionAttestation(... rawProposalHash, verdictHash, executedActionHash ...)` — committed at verdict time, revealed post-execution. + +**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 23 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. + + --- ## Security Considerations From f26805e54fb9401ab138c8c7e650ccac05c63d9f Mon Sep 17 00:00:00 2001 From: babyblueviper1 Date: Fri, 12 Jun 2026 14:59:38 -0400 Subject: [PATCH 30/40] erc-8274: expand WYRIWE subsection per TMerlini (t/28083 #104), conformance-aligned Carries TMerlini's expanded WYRIWE subsection ('drop it in, no PR needed from my side') with three constructions aligned to the filed ERC-8299 normative text per the same-day conformance review: sanitizationPipelineHash keeps the || rawInputHash binding; non-sentinel inputHash = keccak256(sanitized_input) per the verification invariant; the judgment mapping uses the L4 JudgmentExecutionAttestation fields (verdictHash = keccak256(verdict_artifact_ref || rawProposalHash)) rather than overloading L3 fields. Co-authored-by: TMerlini --- ERCS/erc-8274.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index d178ee144f8..dbe9fa20a93 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -535,9 +535,11 @@ else ACP.reject(jobId, verificationDigest, ""); **`inputHash` follows WYRIWE** — `keccak256(sanitized_input)`, binding verification to the full provenance chain. -#### WYRIWE — Input Provenance +#### WYRIWE — Input Provenance (ERC-8299) -WYRIWE defines a triple-hash scheme for input provenance: +WYRIWE makes `IProofVerifier`'s `inputHash` auditable. The base interface commits to a value — WYRIWE commits to *how that value was derived*, binding the signed inference receipt to the provenance chain that produced its input. + +**Triple-hash chain** (normative in ERC-8299): ``` rawInputHash = keccak256(raw_user_input) @@ -545,11 +547,25 @@ sanitizationPipelineHash = keccak256(sanitization_spec_cid || rawInputHash) inputHash = keccak256(sanitized_input) ``` -**Layer separation.** WYRIWE is L3 (input provenance); this ERC is L4 (verification). They compose vertically and are independent. +`sanitizationPipelineHash` binds the public pipeline spec to *this specific raw input* (a pipeline commitment cannot be replayed against a different input), and `inputHash` commits to the exact bytes the model received. The verification invariant: given the three hashes and the public spec at `sanitization_spec_cid`, any verifier can recompute the pipeline over the raw input and confirm `inputHash` — no party is trusted to assert it. The sentinel case (no transformation) is a provable claim, not an assumption: `sanitizationPipelineHash = keccak256(IDENTITY_SENTINEL_CID || rawInputHash)`. + +**Inner layer.** `proofSystem()` returns `"attestation/wyriwe"`. `verify()` recomputes the commitment binding `{agentId, modelHash, inputHash, outputHash, timestamp}`, recovers the signer from the EIP-712 `WyriweAttestation` signature, and checks it against the ERC-8004 registry declared in `agentData` — pure recomputation, no external state reads beyond the registry check. **Layer separation holds:** an operator running only the inner layer gets receipt verification; adding the outer layer gets identity-bound accountability. + +**Judgment as provenance one layer up.** The same chain-of-custody shape maps slot-for-slot onto judgment (ERC-8299 §L4): `rawProposalHash` ↔ `rawInputHash`, `verdictHash` ↔ `sanitizationPipelineHash` (the verdict is the public spec transforming *proposed* → *permitted*), `executedActionHash` ↔ `inputHash`. The binding rule carries over unchanged — `verdictHash = keccak256(verdict_artifact_ref || rawProposalHash)` — so a verdict cannot be shopped against a different proposal, exactly as a pipeline commitment cannot be replayed against a different input. This is the `JudgmentExecutionAttestation` used by the Judgment Validator subsection above; the two attestations compose without sharing fields. + +**Confidence and aggregation.** WYRIWE attestations do not carry a verdict score — they carry a tamper-evident receipt of what ran. Confidence derivation follows the Type A model established above: a pure function of settled commit-reveal records, no trusted updater, no mutable on-chain score. A bare signed receipt without a settled outcome does not satisfy the Type A invariant; Type B (usage-based) weight carries the same self-dealing risk noted above. Aggregation and weighting live in `IAgentVerifier`, above the inner layer. + +**Live proof.** Ledger entry 23 (`api.babyblueviper.com/ledger/23`) is the first production instance of this composition: -**`inputHash` alignment.** `IProofVerifier.verify()`'s `inputHash` maps directly to WYRIWE's `input_hash` — same field, same construction. +| Step | Detail | +| --- | --- | +| Identity | PGA #14, tokenId 14 in the dinamic AgentIdentityRegistry (ERC-8004-style) — mainnet `ownerOf` checkable | +| Provenance | Non-sentinel: `rawProposalHash` → `verdictHash` → `executedActionHash` | +| Verdict | `approve_with_concerns`, confidence 0.85 — concerns: identity-binding, impersonation | +| Timing | Verdict timestamp strictly before execution timestamp — ordering invariant independently verifiable | +| Anchor | Entry 23 verdict event id → TruthAnchorV1 (ERC-8263) — anchor leg pending | -**Ready-made backend.** `WyriweProofVerifier` is already deployed on mainnet, implements `IProofVerifier`, and can be passed directly to any `IAgentVerifier`. +Once the anchor leg posts, all four layers (ERC-8004 identity, ERC-8299 provenance, ERC-8274 judgment, ERC-8263 anchor) are satisfied by a single production entry. #### Judgment Validator — `attestation/judgment` From 3b2f1214dd0b447b0966c08d4dd36082718baf7d Mon Sep 17 00:00:00 2001 From: babyblueviper1 Date: Fri, 12 Jun 2026 15:36:23 -0400 Subject: [PATCH 31/40] erc-8274: note the two-commitment distinction in the WYRIWE subsection (t/28083 #106) Per TMerlini's ask: one note distinguishing sanitizationPipelineHash (pipeline declared + bound to a raw input) from inputHash (what the model received) so the two commitments read as complementary, not contradictory. --- ERCS/erc-8274.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index dbe9fa20a93..36cf3ed04de 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -549,6 +549,8 @@ inputHash = keccak256(sanitized_input) `sanitizationPipelineHash` binds the public pipeline spec to *this specific raw input* (a pipeline commitment cannot be replayed against a different input), and `inputHash` commits to the exact bytes the model received. The verification invariant: given the three hashes and the public spec at `sanitization_spec_cid`, any verifier can recompute the pipeline over the raw input and confirm `inputHash` — no party is trusted to assert it. The sentinel case (no transformation) is a provable claim, not an assumption: `sanitizationPipelineHash = keccak256(IDENTITY_SENTINEL_CID || rawInputHash)`. +**Two commitments, two auditor questions** (they are complementary, not contradictory): `sanitizationPipelineHash` proves *a specific pipeline was declared and bound to a specific raw input* — faithful application is the prover's commitment, not something the hash alone enforces. `inputHash` proves *what the model actually received*. A conformant implementation produces both; the verification invariant (recompute the pipeline over the raw input, confirm `inputHash`) is what ties declaration to delivery. + **Inner layer.** `proofSystem()` returns `"attestation/wyriwe"`. `verify()` recomputes the commitment binding `{agentId, modelHash, inputHash, outputHash, timestamp}`, recovers the signer from the EIP-712 `WyriweAttestation` signature, and checks it against the ERC-8004 registry declared in `agentData` — pure recomputation, no external state reads beyond the registry check. **Layer separation holds:** an operator running only the inner layer gets receipt verification; adding the outer layer gets identity-bound accountability. **Judgment as provenance one layer up.** The same chain-of-custody shape maps slot-for-slot onto judgment (ERC-8299 §L4): `rawProposalHash` ↔ `rawInputHash`, `verdictHash` ↔ `sanitizationPipelineHash` (the verdict is the public spec transforming *proposed* → *permitted*), `executedActionHash` ↔ `inputHash`. The binding rule carries over unchanged — `verdictHash = keccak256(verdict_artifact_ref || rawProposalHash)` — so a verdict cannot be shopped against a different proposal, exactly as a pipeline commitment cannot be replayed against a different input. This is the `JudgmentExecutionAttestation` used by the Judgment Validator subsection above; the two attestations compose without sharing fields. From cbe3812ca87030f7d83be49ff87d21cdc3a5a1d0 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 16:17:55 +0800 Subject: [PATCH 32/40] fix: replace unmerged ERC numbers with descriptive names to pass CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ERC-8299, ERC-8263, ERC-8275 not yet merged — eipw markdown-link-first and HTMLProofer both fail when referenced by number without an existing target file. Replace with WYRIWE, proof anchoring, and settlement periodId respectively. --- ERCS/erc-8274.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 36cf3ed04de..b6d6ff42c7e 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -175,7 +175,7 @@ interface IAgentVerifier { /// @notice Verify an agent's inference claim for a specific task. /// @param taskId Task identifier. Binds verification to a single task. /// Callers SHOULD encode uint256 IDs as bytes32 - /// (e.g. ERC-8183 jobId, ERC-8275 periodId). + /// (e.g. ERC-8183 jobId, settlement periodId). /// @param agentId Identity of the agent that performed the inference. /// Checked against the implementation's stored authorization config. /// @param inputHash Commitment to the model input. @@ -339,7 +339,7 @@ Proof anchoring fills this gap: agents anchor a `proofHash` on-chain at inferenc The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in the anchor registry. | | Purpose | -|--|---------| +|--|-------| | `proofHash` | "This proof was committed at time T" | | `verificationDigest` | "This verification event occurred with these parameters" | @@ -535,11 +535,11 @@ else ACP.reject(jobId, verificationDigest, ""); **`inputHash` follows WYRIWE** — `keccak256(sanitized_input)`, binding verification to the full provenance chain. -#### WYRIWE — Input Provenance (ERC-8299) +#### WYRIWE — Input Provenance WYRIWE makes `IProofVerifier`'s `inputHash` auditable. The base interface commits to a value — WYRIWE commits to *how that value was derived*, binding the signed inference receipt to the provenance chain that produced its input. -**Triple-hash chain** (normative in ERC-8299): +**Triple-hash chain** (normative in WYRIWE): ``` rawInputHash = keccak256(raw_user_input) @@ -553,7 +553,7 @@ inputHash = keccak256(sanitized_input) **Inner layer.** `proofSystem()` returns `"attestation/wyriwe"`. `verify()` recomputes the commitment binding `{agentId, modelHash, inputHash, outputHash, timestamp}`, recovers the signer from the EIP-712 `WyriweAttestation` signature, and checks it against the ERC-8004 registry declared in `agentData` — pure recomputation, no external state reads beyond the registry check. **Layer separation holds:** an operator running only the inner layer gets receipt verification; adding the outer layer gets identity-bound accountability. -**Judgment as provenance one layer up.** The same chain-of-custody shape maps slot-for-slot onto judgment (ERC-8299 §L4): `rawProposalHash` ↔ `rawInputHash`, `verdictHash` ↔ `sanitizationPipelineHash` (the verdict is the public spec transforming *proposed* → *permitted*), `executedActionHash` ↔ `inputHash`. The binding rule carries over unchanged — `verdictHash = keccak256(verdict_artifact_ref || rawProposalHash)` — so a verdict cannot be shopped against a different proposal, exactly as a pipeline commitment cannot be replayed against a different input. This is the `JudgmentExecutionAttestation` used by the Judgment Validator subsection above; the two attestations compose without sharing fields. +**Judgment as provenance one layer up.** The same chain-of-custody shape maps slot-for-slot onto judgment (WYRIWE §L4): `rawProposalHash` ↔ `rawInputHash`, `verdictHash` ↔ `sanitizationPipelineHash` (the verdict is the public spec transforming *proposed* → *permitted*), `executedActionHash` ↔ `inputHash`. The binding rule carries over unchanged — `verdictHash = keccak256(verdict_artifact_ref || rawProposalHash)` — so a verdict cannot be shopped against a different proposal, exactly as a pipeline commitment cannot be replayed against a different input. This is the `JudgmentExecutionAttestation` used by the Judgment Validator subsection above; the two attestations compose without sharing fields. **Confidence and aggregation.** WYRIWE attestations do not carry a verdict score — they carry a tamper-evident receipt of what ran. Confidence derivation follows the Type A model established above: a pure function of settled commit-reveal records, no trusted updater, no mutable on-chain score. A bare signed receipt without a settled outcome does not satisfy the Type A invariant; Type B (usage-based) weight carries the same self-dealing risk noted above. Aggregation and weighting live in `IAgentVerifier`, above the inner layer. @@ -565,9 +565,9 @@ inputHash = keccak256(sanitized_input) | Provenance | Non-sentinel: `rawProposalHash` → `verdictHash` → `executedActionHash` | | Verdict | `approve_with_concerns`, confidence 0.85 — concerns: identity-binding, impersonation | | Timing | Verdict timestamp strictly before execution timestamp — ordering invariant independently verifiable | -| Anchor | Entry 23 verdict event id → TruthAnchorV1 (ERC-8263) — anchor leg pending | +| Anchor | Entry 23 verdict event id → TruthAnchorV1 (proof anchoring) — anchor leg pending | -Once the anchor leg posts, all four layers (ERC-8004 identity, ERC-8299 provenance, ERC-8274 judgment, ERC-8263 anchor) are satisfied by a single production entry. +Once the anchor leg posts, all four layers (ERC-8004 identity, WYRIWE provenance, ERC-8274 judgment, proof anchoring) are satisfied by a single production entry. #### Judgment Validator — `attestation/judgment` From 2a3c2b007396524457fd6ba5e94e73f02f9d014b Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Sat, 13 Jun 2026 16:25:09 +0800 Subject: [PATCH 33/40] fix ci Removed redundant statement about anchor leg satisfaction in ERC-8274 documentation. --- ERCS/erc-8274.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index b6d6ff42c7e..b37beaf5ea3 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -567,8 +567,6 @@ inputHash = keccak256(sanitized_input) | Timing | Verdict timestamp strictly before execution timestamp — ordering invariant independently verifiable | | Anchor | Entry 23 verdict event id → TruthAnchorV1 (proof anchoring) — anchor leg pending | -Once the anchor leg posts, all four layers (ERC-8004 identity, WYRIWE provenance, ERC-8274 judgment, proof anchoring) are satisfied by a single production entry. - #### Judgment Validator — `attestation/judgment` A **judgment claim** asserts that a validator examined a proposed action and issued a verdict on its soundness — in settings where the right answer is not computable at decision time (pre-trade review, contribution-reward evaluation, compliance sign-off). Verification establishes **authenticity, never soundness**: `verify()` answers *"is this authentically the named validator's verdict over exactly this input?"* It MUST NOT be read as *"the action is sound."* From 5dedc35595af9c8a73776f7d980e2678ed5826b4 Mon Sep 17 00:00:00 2001 From: JimmyShi22 <417711026@qq.com> Date: Sat, 13 Jun 2026 22:05:09 +0800 Subject: [PATCH 34/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20babyblueviper1=20(@b?= =?UTF-8?q?abyblueviper1)=20=E4=B8=BA=E5=85=B1=E5=90=8C=E4=BD=9C=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ERCS/erc-8274.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index b37beaf5ea3..d3d53ba541f 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -2,7 +2,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Two-layer interface for on-chain AI inference proof verification, separating IAgentVerifier (application) from IProofVerifier (algorithm) -author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) +author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini), babyblueviper1 (@babyblueviper1) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track From bf574d9667d6de4b3d47e05bdd07f5939e5fecae Mon Sep 17 00:00:00 2001 From: babyblueviper1 Date: Mon, 15 Jun 2026 10:45:02 -0400 Subject: [PATCH 35/40] erc-8274: add committed_at + judgment_type to attestation/judgment Per t/28083 convergence + JimmyShi22 go-ahead (#122). Co-authored-by: Claude Opus 4.8 --- ERCS/erc-8274.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index d3d53ba541f..25b38a22554 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -583,6 +583,15 @@ A **judgment claim** asserts that a validator examined a proposed action and iss Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for judgment claims — absent, not zero-filled. +**`committed_at` and `judgment_type` (REQUIRED for `attestation/*`).** Two fields make the commit-before-outcome guarantee checkable rather than assumed: + +- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **ERC-8263 proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **ERC-8281 / OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (ERC-8281/OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. +- `judgment_type` — discriminates *what* `committed_at` is checked against: + - `outcome_verifiable` (Type A): `committed_at` MUST predate the realized outcome's settlement. + - `consensus_weighted` (Type B): `committed_at` MUST predate the reveal. + +The field is universal across `attestation/*`; the `judgment_type` discriminator carries the per-type reference point — which is why the two are specified together. + **How the deterministic bool emerges.** Judgment is non-deterministic; the interface output is not. Aggregation lives in `IAgentVerifier` (never the inner layer), by claim type: - **Type A — outcome-verifiable.** Validator confidence weights are *derived* as a pure function of settled commit-reveal records (verdicts committed on-chain before outcomes, revealed after) — recomputable by any party from chain state, with no updater-trust problem. **Outcome-oracle dependency, stated explicitly:** this recomputation is trustless only where outcomes settle on-chain; off-chain-settled outcomes (an exchange account, a counterparty system) require an outcome oracle, and the aggregation inherits that oracle's trust assumptions. Consumers MUST be able to distinguish on-chain-settled from oracle-attested records. @@ -594,13 +603,13 @@ The resulting bool gates settlement exactly like any other backend (see the ERC- 1. Losses MUST be present — a record showing only wins is marketing, not accountability. 2. Outcomes MUST settle somewhere the validator cannot edit. -3. The pre-outcome timestamp MUST be anchored at issue time to a system the validator does not control (the same primitive as OCP's observation commitment). +3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the ERC-8281/OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`. **Execution binding (optional).** Where the judged action is subsequently executed, the reviewed→executed chain of custody binds with the WYRIWE L4 attestation — `JudgmentExecutionAttestation(... rawProposalHash, verdictHash, executedActionHash ...)` — committed at verdict time, revealed post-execution. -**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 23 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. +**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 26 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. --- From b749dc47f353caa406e419f0f79f7b0817380abf Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 16 Jun 2026 10:30:35 +0800 Subject: [PATCH 36/40] feat: add block.timestamp to verificationDigest preimage and VerificationCompleted event --- ERCS/erc-8274.md | 49 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 25b38a22554..388580696bd 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -2,7 +2,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Two-layer interface for on-chain AI inference proof verification, separating IAgentVerifier (application) from IProofVerifier (algorithm) -author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini), babyblueviper1 (@babyblueviper1) +author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track @@ -29,11 +29,11 @@ Verification infrastructure already exists, but it is highly fragmented. **Verification paradigms already live:** -| Paradigm | Description | -| ----------- | ---------------------------------------------------------------------------------------- | -| zkML | Cryptographic proof that a specific model produced a given output from a given input | -| opML | Optimistic AI inference execution with a challenge window for fraud proofs | -| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | +| Paradigm | Description | +| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| zkML | Cryptographic proof that a specific model produced a given output from a given input | +| opML | Optimistic AI inference execution with a challenge window for fraud proofs | +| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | | Attestation | Off-chain inference result certified by one or more authorized signers — covers oracle gateways (e.g. Chainlink), multisig / AVS validator networks (e.g. EigenLayer), and judgment validators | **ERCs that need inference verification:** @@ -169,7 +169,8 @@ interface IAgentVerifier { bool valid, bytes32 inputHash, bytes32 outputHash, - bytes32 agentProofProfile // fingerprint of the verification logic used for this event + bytes32 agentProofProfile, // fingerprint of the verification logic used for this event + uint256 timestamp // block.timestamp at verification time; included in preimage ); /// @notice Verify an agent's inference claim for a specific task. @@ -183,9 +184,9 @@ interface IAgentVerifier { /// @param proof Cryptographic evidence, passed unchanged to the inner IProofVerifier(s). /// @return valid Whether the agent is authorized and the proof is valid. /// @return verificationDigest Digest fingerprinting this verification event, computed from - /// taskId, agentId, inputHash, outputHash, valid, and agentProofProfile. - /// Returned regardless of outcome. MAY be used as an on-chain - /// audit anchor (e.g. ERC-8183 job.reason). + /// taskId, agentId, inputHash, outputHash, valid, agentProofProfile, + /// and block.timestamp. Returned regardless of outcome. MAY be used + /// as an on-chain audit anchor (e.g. ERC-8183 job.reason). /// @dev NOT view — implementations MAY write state (e.g. single-use taskId tracking). function verify( bytes32 taskId, @@ -213,10 +214,10 @@ This ERC does not mandate the internal structure of `IAgentVerifier` implementat `verify()` returns `(bool valid, bytes32 verificationDigest)`. The `verificationDigest` is a commitment to the full verification event, computed from: ``` -keccak256(abi.encode(taskId, agentId, inputHash, outputHash, valid, agentProofProfile)) +keccak256(abi.encode(taskId, agentId, inputHash, outputHash, valid, agentProofProfile, block.timestamp)) ``` -Including `valid` and `agentProofProfile` ensures that the same inputs verified by different proof systems, or with different outcomes, produce different digests. +Including `valid`, `agentProofProfile`, and `block.timestamp` ensures that the same inputs verified by different proof systems, at different times, or with different outcomes, produce different digests. `block.timestamp` makes the digest self-contained — the verification time is encoded directly rather than requiring block lookup. `VerificationCompleted` SHOULD be emitted on every call — passing and failing — carrying the same fields as the preimage. This follows OCP's commitment model: any external observer can independently verify a `VerificationCompleted` record by applying the recompute → compare → confirm inclusion procedure, without calling any contract and trusting any intermediary. @@ -282,7 +283,7 @@ recompute → compare → confirm inclusion This ERC adopts OCP as the unifying model for `IAgentVerifier` events — not only because every proof backend satisfies the primitive, but because `VerificationCompleted` maps directly onto it: the event is the observation, `verificationDigest` is the commitment, and the emitted fields are the preimage. -`verificationDigest` is computed from `(taskId, agentId, inputHash, outputHash, valid, agentProofProfile)`. The event carries those same fields alongside the digest, making every record self-describing and independently auditable: +`verificationDigest` is computed from `(taskId, agentId, inputHash, outputHash, valid, agentProofProfile, block.timestamp)`. The event carries those same fields alongside the digest, making every record self-describing and independently auditable: - **On-chain**: recompute the digest from held parameters and compare against what was emitted - **Off-chain**: apply all three steps — recompute from emitted fields, compare, confirm event inclusion @@ -339,7 +340,7 @@ Proof anchoring fills this gap: agents anchor a `proofHash` on-chain at inferenc The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in the anchor registry. | | Purpose | -|--|-------| +|--|---------| | `proofHash` | "This proof was committed at time T" | | `verificationDigest` | "This verification event occurred with these parameters" | @@ -449,12 +450,13 @@ contract AgentVerifier is IAgentVerifier { } bytes32 agentProofProfile = _verifier.proofProfile(); + uint256 ts = block.timestamp; verificationDigest = keccak256(abi.encode( - taskId, agentId, inputHash, outputHash, valid, agentProofProfile + taskId, agentId, inputHash, outputHash, valid, agentProofProfile, ts )); emit VerificationCompleted( - taskId, agentId, verificationDigest, valid, inputHash, outputHash, agentProofProfile + taskId, agentId, verificationDigest, valid, inputHash, outputHash, agentProofProfile, ts ); } } @@ -567,6 +569,8 @@ inputHash = keccak256(sanitized_input) | Timing | Verdict timestamp strictly before execution timestamp — ordering invariant independently verifiable | | Anchor | Entry 23 verdict event id → TruthAnchorV1 (proof anchoring) — anchor leg pending | +Once the anchor leg posts, all four layers (ERC-8004 identity, WYRIWE provenance, ERC-8274 judgment, proof anchoring) are satisfied by a single production entry. + #### Judgment Validator — `attestation/judgment` A **judgment claim** asserts that a validator examined a proposed action and issued a verdict on its soundness — in settings where the right answer is not computable at decision time (pre-trade review, contribution-reward evaluation, compliance sign-off). Verification establishes **authenticity, never soundness**: `verify()` answers *"is this authentically the named validator's verdict over exactly this input?"* It MUST NOT be read as *"the action is sound."* @@ -583,15 +587,6 @@ A **judgment claim** asserts that a validator examined a proposed action and iss Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for judgment claims — absent, not zero-filled. -**`committed_at` and `judgment_type` (REQUIRED for `attestation/*`).** Two fields make the commit-before-outcome guarantee checkable rather than assumed: - -- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **ERC-8263 proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **ERC-8281 / OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (ERC-8281/OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. -- `judgment_type` — discriminates *what* `committed_at` is checked against: - - `outcome_verifiable` (Type A): `committed_at` MUST predate the realized outcome's settlement. - - `consensus_weighted` (Type B): `committed_at` MUST predate the reveal. - -The field is universal across `attestation/*`; the `judgment_type` discriminator carries the per-type reference point — which is why the two are specified together. - **How the deterministic bool emerges.** Judgment is non-deterministic; the interface output is not. Aggregation lives in `IAgentVerifier` (never the inner layer), by claim type: - **Type A — outcome-verifiable.** Validator confidence weights are *derived* as a pure function of settled commit-reveal records (verdicts committed on-chain before outcomes, revealed after) — recomputable by any party from chain state, with no updater-trust problem. **Outcome-oracle dependency, stated explicitly:** this recomputation is trustless only where outcomes settle on-chain; off-chain-settled outcomes (an exchange account, a counterparty system) require an outcome oracle, and the aggregation inherits that oracle's trust assumptions. Consumers MUST be able to distinguish on-chain-settled from oracle-attested records. @@ -603,13 +598,13 @@ The resulting bool gates settlement exactly like any other backend (see the ERC- 1. Losses MUST be present — a record showing only wins is marketing, not accountability. 2. Outcomes MUST settle somewhere the validator cannot edit. -3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the ERC-8281/OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. +3. The pre-outcome timestamp MUST be anchored at issue time to a system the validator does not control (the same primitive as OCP's observation commitment). Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`. **Execution binding (optional).** Where the judged action is subsequently executed, the reviewed→executed chain of custody binds with the WYRIWE L4 attestation — `JudgmentExecutionAttestation(... rawProposalHash, verdictHash, executedActionHash ...)` — committed at verdict time, revealed post-execution. -**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 26 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. +**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 23 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. --- From 47f5ba74ac8d28e432511aca9909c47e7f7996a5 Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 16 Jun 2026 11:49:03 +0800 Subject: [PATCH 37/40] fix: restore babyblueviper1 changes + add block.timestamp to verificationDigest --- ERCS/erc-8274.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 388580696bd..007707a9bc5 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -2,7 +2,7 @@ eip: 8274 title: AI Inference Proof Verification Interfaces description: Two-layer interface for on-chain AI inference proof verification, separating IAgentVerifier (application) from IProofVerifier (algorithm) -author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini) +author: JimmyShi22 (@JimmyShi22) , Damonzwicker (@damonzwicker), TMerlini (@Echo-Merlini), babyblueviper1 (@babyblueviper1) discussions-to: https://ethereum-magicians.org/t/draft-erc-universal-ai-inference-verification-registry/28083 status: Draft type: Standards Track @@ -29,11 +29,11 @@ Verification infrastructure already exists, but it is highly fragmented. **Verification paradigms already live:** -| Paradigm | Description | -| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| zkML | Cryptographic proof that a specific model produced a given output from a given input | -| opML | Optimistic AI inference execution with a challenge window for fraud proofs | -| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | +| Paradigm | Description | +| ----------- | ---------------------------------------------------------------------------------------- | +| zkML | Cryptographic proof that a specific model produced a given output from a given input | +| opML | Optimistic AI inference execution with a challenge window for fraud proofs | +| TEE | AI inference run inside a hardware-isolated enclave with a verifiable attestation report | | Attestation | Off-chain inference result certified by one or more authorized signers — covers oracle gateways (e.g. Chainlink), multisig / AVS validator networks (e.g. EigenLayer), and judgment validators | **ERCs that need inference verification:** @@ -340,7 +340,7 @@ Proof anchoring fills this gap: agents anchor a `proofHash` on-chain at inferenc The anchor check is an application-layer concern — it belongs in `IAgentVerifier`, not `IProofVerifier`. Implementations can accept a Merkle inclusion proof inside `proof` to confirm `proofHash` exists in the anchor registry. | | Purpose | -|--|---------| +|--|-------| | `proofHash` | "This proof was committed at time T" | | `verificationDigest` | "This verification event occurred with these parameters" | @@ -569,8 +569,6 @@ inputHash = keccak256(sanitized_input) | Timing | Verdict timestamp strictly before execution timestamp — ordering invariant independently verifiable | | Anchor | Entry 23 verdict event id → TruthAnchorV1 (proof anchoring) — anchor leg pending | -Once the anchor leg posts, all four layers (ERC-8004 identity, WYRIWE provenance, ERC-8274 judgment, proof anchoring) are satisfied by a single production entry. - #### Judgment Validator — `attestation/judgment` A **judgment claim** asserts that a validator examined a proposed action and issued a verdict on its soundness — in settings where the right answer is not computable at decision time (pre-trade review, contribution-reward evaluation, compliance sign-off). Verification establishes **authenticity, never soundness**: `verify()` answers *"is this authentically the named validator's verdict over exactly this input?"* It MUST NOT be read as *"the action is sound."* @@ -587,6 +585,15 @@ A **judgment claim** asserts that a validator examined a proposed action and iss Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for judgment claims — absent, not zero-filled. +**`committed_at` and `judgment_type` (REQUIRED for `attestation/*`).** Two fields make the commit-before-outcome guarantee checkable rather than assumed: + +- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **ERC-8263 proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **ERC-8281 / OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (ERC-8281/OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. +- `judgment_type` — discriminates *what* `committed_at` is checked against: + - `outcome_verifiable` (Type A): `committed_at` MUST predate the realized outcome's settlement. + - `consensus_weighted` (Type B): `committed_at` MUST predate the reveal. + +The field is universal across `attestation/*`; the `judgment_type` discriminator carries the per-type reference point — which is why the two are specified together. + **How the deterministic bool emerges.** Judgment is non-deterministic; the interface output is not. Aggregation lives in `IAgentVerifier` (never the inner layer), by claim type: - **Type A — outcome-verifiable.** Validator confidence weights are *derived* as a pure function of settled commit-reveal records (verdicts committed on-chain before outcomes, revealed after) — recomputable by any party from chain state, with no updater-trust problem. **Outcome-oracle dependency, stated explicitly:** this recomputation is trustless only where outcomes settle on-chain; off-chain-settled outcomes (an exchange account, a counterparty system) require an outcome oracle, and the aggregation inherits that oracle's trust assumptions. Consumers MUST be able to distinguish on-chain-settled from oracle-attested records. @@ -598,13 +605,13 @@ The resulting bool gates settlement exactly like any other backend (see the ERC- 1. Losses MUST be present — a record showing only wins is marketing, not accountability. 2. Outcomes MUST settle somewhere the validator cannot edit. -3. The pre-outcome timestamp MUST be anchored at issue time to a system the validator does not control (the same primitive as OCP's observation commitment). +3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the ERC-8281/OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`. **Execution binding (optional).** Where the judged action is subsequently executed, the reviewed→executed chain of custody binds with the WYRIWE L4 attestation — `JudgmentExecutionAttestation(... rawProposalHash, verdictHash, executedActionHash ...)` — committed at verdict time, revealed post-execution. -**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 23 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. +**Production reference.** `https://api.babyblueviper.com/ledger` — a judgment validator running against real capital: 26 signed entries, 10 wins / 9 losses across 19 settled outcomes (losses published by design); every verdict relay-anchored at issue time with per-entry retention status; evidence-separability sub-paths live; first on-chain commit-reveal settlement of a judgment attestation on Sepolia (`GenericCommitRevealSettler`, entry 19 — `committedAt < revealedAt` checkable on-chain); and a live cross-stack trace (entry 23) binding a registry identity through a signed pre-action verdict to an executed action via the triple-hash. Offered as reference data, not a required format. --- From 10ed575e511bc96c74d4c72a87b61cc3051e4b2a Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 16 Jun 2026 12:05:55 +0800 Subject: [PATCH 38/40] feat: add block.timestamp to verificationDigest preimage and VerificationCompleted event --- ERCS/erc-8274.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 007707a9bc5..fb2d45b392a 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -185,8 +185,8 @@ interface IAgentVerifier { /// @return valid Whether the agent is authorized and the proof is valid. /// @return verificationDigest Digest fingerprinting this verification event, computed from /// taskId, agentId, inputHash, outputHash, valid, agentProofProfile, - /// and block.timestamp. Returned regardless of outcome. MAY be used - /// as an on-chain audit anchor (e.g. ERC-8183 job.reason). + /// and block.timestamp. Returned regardless of outcome. MAY be used as an on-chain + /// audit anchor (e.g. ERC-8183 job.reason). /// @dev NOT view — implementations MAY write state (e.g. single-use taskId tracking). function verify( bytes32 taskId, From 4f81a0d3d5b136536f4620bae3c9b364b31c231c Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 16 Jun 2026 14:32:01 +0800 Subject: [PATCH 39/40] fix: replace ERC-8281 with OCP, link ERC-8263 to fix markdown-link-first CI --- ERCS/erc-8274.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index fb2d45b392a..791907cea9a 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -587,7 +587,7 @@ Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for **`committed_at` and `judgment_type` (REQUIRED for `attestation/*`).** Two fields make the commit-before-outcome guarantee checkable rather than assumed: -- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **ERC-8263 proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **ERC-8281 / OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (ERC-8281/OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. +- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **[ERC-8263](https://github.com/ethereum/ERCs/pull/1748) proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. - `judgment_type` — discriminates *what* `committed_at` is checked against: - `outcome_verifiable` (Type A): `committed_at` MUST predate the realized outcome's settlement. - `consensus_weighted` (Type B): `committed_at` MUST predate the reveal. @@ -605,7 +605,7 @@ The resulting bool gates settlement exactly like any other backend (see the ERC- 1. Losses MUST be present — a record showing only wins is marketing, not accountability. 2. Outcomes MUST settle somewhere the validator cannot edit. -3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the ERC-8281/OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. +3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`. From 7b3ee8cc3e4637ea9d9e9ff4049f2f94bb9f211d Mon Sep 17 00:00:00 2001 From: jimmyshi <417711026@qq.com> Date: Tue, 16 Jun 2026 14:46:54 +0800 Subject: [PATCH 40/40] fix: replace ERC-8263 with proof anchoring to fix markdown-rel-links CI --- ERCS/erc-8274.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-8274.md b/ERCS/erc-8274.md index 791907cea9a..03f0db3b173 100644 --- a/ERCS/erc-8274.md +++ b/ERCS/erc-8274.md @@ -587,7 +587,7 @@ Judgment verdicts are trinary, not binary. `codeMeasurement` MUST be absent for **`committed_at` and `judgment_type` (REQUIRED for `attestation/*`).** Two fields make the commit-before-outcome guarantee checkable rather than assumed: -- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **[ERC-8263](https://github.com/ethereum/ERCs/pull/1748) proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (OCP) -> verdict-commitment (ERC-8263) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. +- `committed_at` — the timestamp at which the *verdict* was committed, sourced from the **proof anchoring proofHash leg** (where `proofHash` is the verdict event id). This is a distinct commitment target from the **OCP anchor**, which commits the *input* (the prompt/task — *when it was issued*). The two anchor different things at different points in the chain — input-commitment (OCP) -> verdict-commitment (proof anchoring) -> settlement — and a verifier MUST treat them as separate, never substituting one for the other. `committed_at` MUST be provably prior to the outcome the verdict is graded against. - `judgment_type` — discriminates *what* `committed_at` is checked against: - `outcome_verifiable` (Type A): `committed_at` MUST predate the realized outcome's settlement. - `consensus_weighted` (Type B): `committed_at` MUST predate the reveal. @@ -605,7 +605,7 @@ The resulting bool gates settlement exactly like any other backend (see the ERC- 1. Losses MUST be present — a record showing only wins is marketing, not accountability. 2. Outcomes MUST settle somewhere the validator cannot edit. -3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the ERC-8263 proofHash leg — NOT the OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. +3. The pre-outcome timestamp (`committed_at`, above) MUST be anchored at issue time to a system the validator does not control. For the verdict this is the proof anchoring proofHash leg — NOT the OCP input anchor (which commits the input, not the verdict; see `committed_at` above). It is the same kind of primitive as OCP's observation commitment, applied one layer up to the verdict. Commitment and outcome evidence MUST be separately addressable: `{recordPointer}/commitment` and `{recordPointer}/outcome`.