ERC-8126 - AI Agent Verification

Created 2026-01-15
Status Review
Category ERC
Type Standards Track
Authors
Requires

Abstract

This ERC defines a standard interface for verifying AI agents on Ethereum that have been registered via ERC-8004. It enables AI agents to undergo several specialized verification processes defined in this proposal: Ethereum Token Verification (ETV), Media Content Verification (MCV), Solidity Code Verification (SCV), Web Application Verification (WAV), and Wallet Verification (WV). Verification providers implement this standard using Private Data Verification (PDV) to generate Zero-Knowledge Proofs (ZKPs). Detailed verification results are accessible only to the AI agent’s wallet holder and include a unified risk score (0-100) to help users assess the agent’s trustworthiness. Verification attestations can additionally be posted to ERC-8004’s Validation Registry for ecosystem-wide discoverability.

Motivation

As AI agents become increasingly prevalent in blockchain ecosystems, users need standardized ways to verify their authenticity and trustworthiness. Current solutions are fragmented, with no unified standard for agent registration or verification. This ERC addresses these challenges by providing:

  1. Multi-Layer Verification: Five specialized verification types assess different aspects of agent security
  2. Privacy-First Architecture: ZKPs ensure verification without exposing sensitive data
  3. Unified Risk Scoring: A standardized 0-100 risk score enables easy comparison between agents
  4. Quantum-Resistant Future: Optional Quantum Cryptography Verification (QCV) provides future-proof encryption
  5. Integration with ERC-8004: Leverages portable ERC-721 identities and pluggable validation/reputation registries for broader trust signals
Term Definition
Agent Wallet The Ethereum address designated as controlled by the AI agent
AI Agent An autonomous software entity identified by an ERC-8004 Identity Registry token
C2PA Coalition for Content Provenance and Authenticity - the standards body responsible for the open specification used to embed tamper-evident provenance and authenticity information in digital media
ETV Ethereum Token Verification - validates smart contract presence and legitimacy
MCV Media Content Verification - validates the authenticity, provenance, and integrity of digital media
OWASP Open Worldwide Application Security Project - nonprofit organization providing security standards and testing guides for web and smart contract applications
PDV Private Data Verification - generates ZKPs from verification results
Proof ID A unique identifier for a ZKP generated during verification
QCV Quantum Cryptography Verification - provides quantum-resistant encryption for sensitive data
Risk Score A numerical value from 0-100 indicating the assessed risk level, where 0 is the lowest risk, and 100 is the highest risk
SCV Solidity Code Verification - validates Solidity Code security
Verification Provider A service implementing this standard's verification types (ETV, MCV, PDV, QCV, SCV, WAV, WV)
WAV Web Application Verification - checks endpoint security and accessibility
WV Wallet Verification - assesses wallet history and threat database status
ZKP Zero-Knowledge Proof - cryptographic proof that verification occurred without revealing underlying data

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.

Verification Flow

The following diagram illustrates the verification process:

ERC-8126 AI Agent Verification - Verification Flow Diagram

Verification Types

Verification requests MUST reference an ERC-8004 agentId (uint256 token ID from the Identity Registry).

The verification provider MUST call tokenURI(agentId) on the canonical Identity Registry contract and resolve the returned URI to fetch the agent registration JSON file. All metadata fields (agentWallet/walletAddress, chain_id, contractAddress, endpoints/url, image/imageUrl, platform_id, solidityCode, etc.) MUST be extracted from this JSON in accordance with the ERC-8004 registration schema.

Direct submission of individual parameters (agentWallet/walletAddress, chain_id, contractAddress, endpoints/url, image/imageUrl, platform_id, solidityCode, etc.) without an agentId is NOT permitted.

Compliant verification providers MUST implement all of the following verification types and apply them using the resolved metadata:

Ethereum Token Verification (ETV)

Validates the legitimacy and security of the smart contract when a contractAddress is present in the resolved metadata.

Media Content Verification (MCV)

Validates the authenticity, provenance, and integrity of the media content when imageUrl is present in the resolved metadata.

Solidity Code Verification (SCV)

Validates the legitimacy and security of the solidity code when solidityCode is present in the resolved metadata.

Web Application Verification (WAV)

Ensures the agent's web endpoint is accessible and secure using resolved metadata.

Wallet Verification (WV)

Confirms wallet ownership and assesses on-chain risk profile using resolved metadata.

Integration with ERC-8004

Verification providers MAY post final risk scores and Proof IDs as attestations to the ERC-8004 Validation Registry using its pluggable validation interface. This enables portable, discoverable security attestations alongside reputation signals.

Off-chain Verification

Verification is performed off-chain to:

  1. Eliminate gas costs for verification operations
  2. Enable complex verification logic that would be prohibitively expensive on-chain
  3. Allow verification criteria to evolve without requiring contract upgrades
  4. Enable multiple competing verification providers

Payment Protocol

Verification providers MAY charge fees for verification services. When fees are required:

Risk Scoring

The overall risk score MUST be calculated as the mean of all applicable verification scores:

Tier Score Range Description
Low Risk 0-20 Minimal concerns identified
Moderate 21-40 Some concerns, review recommended
Elevated 41-60 Notable concerns, caution advised
High Risk 61-80 Significant concerns detected
Critical 81-100 Severe concerns, avoid interaction

Error Codes

Implementations MUST use the following standardized error codes:

Error Code Name Description
0x01 InvalidAddress Provided address is not a valid Ethereum address
0x02 InvalidURL Provided URL is malformed or not HTTPS
0x03 AgentNotFound No agent exists with the specified agentId
0x04 VerificationFailed Verification provider returned an error
0x05 InsufficientCredits No verification credits available
0x06 InvalidProof PDV proof validation failed
0x07 ProviderUnavailable Verification provider is not responding
0x08 InvalidScore Risk score outside valid range (0-100)
0x09 ContractNotFound Specified contract does not exist on chain
0x0A SolidityCodeNotFound Specified Solidity Code does not exist
0x0B ImageNotFound Image could not be resolved or fetched from agent registration metadata
0x0C SteganographyFailed Steganographic payload extraction failed (technical error)
0x0D MediaVerificationFailed General failure in media integrity or provenance verification

Implementations SHOULD revert with these error codes:

     error InvalidAddress();
     error InvalidURL();
     error AgentNotFound();
     error VerificationFailed();
     error InsufficientCredits();
     error InvalidProof();
     error ProviderUnavailable();
     error InvalidScore();
     error ContractNotFound();
     error SolidityCodeNotFound();
     error ImageNotFound();
     error SteganographyFailed();
     error MediaVerificationFailed();

Interface

This ERC is primarily an off-chain standard for verification providers. No on-chain smart contract interface is required to submit verification requests or perform the verification types (ETV, MCV, SCV, WAV, WV, PDV, QCV).

Optional on-chain components MAY be implemented by providers or integrators to:

If an on-chain component is deployed, it SHOULD include at minimum:

     ```solidity
     // SPDX-License-Identifier: CC0-1.0
     pragma solidity ^0.8.0;

     interface IERC8126 {
         /// @notice Emitted when an agent is verified
         event AgentVerified(
             uint256 indexed agentId,          // Token ID (ERC-721) from ERC-8004 Identity Registry
             uint8 overallRiskScore,
             bytes32 etvProofId,
             bytes32 mcvProofId,
             bytes32 scvProofId,
             bytes32 wavProofId,
             bytes32 wvProofId,
             bytes32 summaryProofId
         );

         /// @notice Emitted when an attestation is posted to the ERC-8004 Validation Registry
         event AttestationPosted(
             uint256 indexed agentId,
             uint8 riskScore,
             bytes32 proofId
         );

         /// @notice Optional: Query the latest risk score for an agentId
         /// @dev MAY revert if no verification exists
         function getLatestRiskScore(uint256 agentId) external view returns (uint8);
     }

Rationale

Required Standards Justification

EIP-155 (Replay Protection): Verification requests involve signed messages from agent owners to authorize providers or payments. Without chain ID inclusion EIP-155, a signed request on mainnet could be replayed on testnets or L2s, potentially triggering unwanted verifications or duplicate payments across chains.

EIP-191 (Signed Data Standard): Wallet verification and request authorization require proving control over the agent wallet. EIP-191 provides a standardised prefix for signed messages, ensuring compatibility across wallets and preventing signature malleability during verification.

EIP-712 (Typed Data Signing): Verification requests use structured data (agentId, metadata hashes, nonce, payment details). EIP-712 enables human-readable signing prompts (e.g., "Authorize Verification for Agent ID: 1234 on chain 1") instead of blind hashes, reducing phishing risks and improving UX for agent owners.

ERC-3009 (Transfer With Authorization): Verification fees are paid via ERC-3009, which enables gasless USDC transfers, with the provider covering gas costs, making verification accessible without requiring users to hold ETH.

ERC-8004 (Trustless Agents Registry): Builds on the canonical ERC-721 Non-Fungible Token Standard (with ERC721URIStorage) for the Identity Registry, where agents are minted as unique NFTs for portable, censorship-resistant identities. ERC-8004 defines agentId (as ERC-721 tokenId), tokenURI'-based metadata resolution (e.g.,name,walletAddress,endpoints,contractAddress` in JSON), optional on-chain metadata, and posting to the Validation Registry for composable trust signals (reputation, proofs, validations) after verification flows complete.

Five Verification Types

The five verification types are presented in alphabetical order (ETV → MCV → SCV → WAV → WV) for clarity and consistency.

The decision to implement five distinct verification types addresses different aspects of agent authenticity:

Risk Scoring Approach

A unified 0-100 risk scoring system allows:

Provider Agnostic Design

This standard intentionally separates the interface specification from implementation details. Any verification provider may implement compliant ETV, MCV, SCV, WAV, WV, PDV and QCV services, enabling:

  1. Competition among verification providers
  2. Specialization in different verification domains
  3. Geographic and jurisdictional flexibility
  4. Price competition benefiting users

Privacy-First Architecture with PDV

Verification results are processed through PDV, which generates ZKPs. This privacy-first approach:

  1. Eliminates data breach risks - no stored data means nothing to compromise
  2. Provides cryptographic proof of verification that third parties can validate
  3. Ensures GDPR and privacy regulation compliance
  4. Builds user trust through transparent, verifiable data handling

Quantum-Resistant Future with QCV

Verification providers may implement QCV to quantum-resistant encrypt sensitive verification data.

QCV Key Properties: - Provides future-proof protection against quantum computing threats - Military-grade encryption standards (AES-256-GCM) - Enables secure long-term storage of verification records

Backwards Compatibility

This ERC introduces a new standard focused on verification and does not modify any existing standards. It requires agents to be registered via ERC-8004, which provides portable ERC-721-based identities and metadata resolution.

Pre-existing implementations that relied on the original custom registration logic in this ERC would need to migrate by:

Existing AI agents already registered via ERC-8004 can undergo verification without changes. The standard is designed to work alongside existing token standards (ERC-20, ERC-721, ERC-1155) and identity standards.

Test Cases

Verification Tests

ETV Completes with contractAddress

Ensures ETV succeeds when metadata includes contractAddress.

function testETVCompletesWhenContractAddressPresent() public {
    uint256 agentId = 1;
    vm.prank(user);
    // bytes32 proofId = verifier.verifyETV(agentId);
}

MCV Completes with imageUrl

Ensures SCV succeeds when imageUrl is present.

function testMCVCompletesWhenimageUrlPresent() public {
    uint256 agentId = 42;
    vm.prank(user);
    // verifier.verifyMCV(agentId);
}

SCV Completes with solidityCode

Ensures SCV succeeds when solidityCode is present.

function testSCVCompletesWhensolidityCodePresent() public {
    uint256 agentId = 42;
    vm.prank(user);
    // verifier.verifySCV(agentId);
}

WAV Completes for All agentIds

Verifies WAV executes correctly for a range of agentIds.

function testWAVCompletesForAllAgentIds() public {
    uint256;
    ids[0] = 10; ids[1] = 20; ids[2] = 30;

    for (uint i = 0; i < ids.length; i++) {
        vm.prank(user);
        // verifier.verifyWAV(ids[i]);
    }
}

WV Completes for All agentIds

Checks WV runs successfully across multiple agentIds.

function testWVCompletesForAllAgentIds() public {
    uint256;
    ids[0] = 10; ids[1] = 20; ids[2] = 30;

    for (uint i = 0; i < ids.length; i++) {
        vm.prank(user);
        // verifier.verifyWV(ids[i]);
    }
}

Generates PDV ZKPs

Confirms all proof types are generated for an agentId.

function testGeneratesPDVZKPForEachType() public {
    uint256 agentId = 100;
    vm.prank(user);
    // verifier.verifyAgent(agentId);
}

Calculates overallRiskScore

Validates the mean overallRiskScore calculation.

function testCalculatesOverallRiskScore() public {
    uint8 score = verifier.calculateRiskScore(10, 20, 30, 40);
    assertEq(score, 25);
}

Emits AgentVerified Event

Checks event emission with proof IDs.

function testEmitsAgentVerifiedEvent() public {
    uint256 agentId = 999;
    vm.expectEmit(true, true, true, true);
    emit AgentVerified(agentId, 45, [bytes32(1), bytes32(2), bytes32(3), bytes32(4)]);
}

Reverts with VerificationFailed

Ensures provider failure triggers VerificationFailed.

function testRevertsWithVerificationFailed() public {
    vm.expectRevert(VerificationFailed.selector);
}

Reverts with InsufficientCredits

Checks users without credits are blocked via InsufficientCredits.

function testRevertsWithInsufficientCredits() public {
    vm.prank(poorUser);
    vm.expectRevert(InsufficientCredits.selector);
}

Access Control

Unauthorized Proof Access

Prevents non-owners from accessing proofs.

function testUnauthorizedProofAccess() public {
    vm.prank(0xBBBB);
    vm.expectRevert(UnauthorizedAccess.selector);
    registry.getAgentProofs(1234);
}

Risk Score

Risk Tier Classification

Ensures scores map correctly to RiskTier.

function testRiskScoreTiers() public {
    assertEq(verifier.getRiskTier(15), RiskTier.Low);
    assertEq(verifier.getRiskTier(35), RiskTier.Moderate);
}

Reference Implementation

import crypto from 'crypto';
import { createPublicClient, http, getAddress, parseAbi } from 'viem';

class ERC8126Error extends Error {
  constructor(
    public code: number,
    message: string
  ) {
    super(message);
    this.name = 'ERC8126Error';
  }
}

enum VerificationStatus {
  Passed = 'passed',
  Failed = 'failed',
  Inconclusive = 'inconclusive',
}

enum RiskTier {
  Low = 'low',
  Moderate = 'moderate',
  Elevated = 'elevated',
  HighRisk = 'high',
  Critical = 'critical',
}

interface AgentMetadata {
  contractAddress?: string;
  solidityCode?: string;
  url?: string;
  walletAddress?: string;
  chain_id?: number;
  [key: string]: any;
}

interface VerificationProviderConfig {
  chainId?: number;
  identityRegistry?: string;
  validationRegistry?: string;
  rpcUrl?: string;
}

interface VerificationResult {
  type: string;
  status: VerificationStatus;
  score: number;
  proofId: string;
}

const ERC8004_ABI = parseAbi([
  'function tokenURI(uint256 tokenId) external view returns (string)',
]);

async function resolveAgentMetadata(
  agentId: bigint,
  config: VerificationProviderConfig
): Promise<AgentMetadata> {
  if (!config.identityRegistry) {
    throw new ERC8126Error(0x03, 'ERC-8004 Identity Registry address is required');
  }
  if (!config.rpcUrl) {
    throw new ERC8126Error(0x04, 'RPC URL is required to resolve ERC-8004 metadata');
  }

  const client = createPublicClient({
    chain: { id: config.chainId || 1, name: 'Ethereum', nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 } },
    transport: http(config.rpcUrl),
  });

  try {
    const uri = await client.readContract({
      address: getAddress(config.identityRegistry),
      abi: ERC8004_ABI,
      functionName: 'tokenURI',
      args: [agentId],
    });

    if (!uri || typeof uri !== 'string') {
      throw new ERC8126Error(0x05, 'Invalid tokenURI returned from ERC-8004 registry');
    }

    const response = await fetch(uri);
    if (!response.ok) {
      throw new ERC8126Error(0x06, `Failed to fetch metadata from ${uri}`);
    }

    const metadata: AgentMetadata = await response.json();

    return {
      contractAddress: metadata.contractAddress ? getAddress(metadata.contractAddress) : undefined,
      imageUrl: metadata.imageUrl ? getAddress(metadata.imageUrl) : undefined,
      solidityCode: metadata.solidityCode ? getAddress(metadata.solidityCode) : undefined,
      walletAddress: metadata.walletAddress ? getAddress(metadata.walletAddress) : undefined,
      url: metadata.url,
      chain_id: metadata.chain_id,
      ...metadata,
    };
  } catch (error) {
    if (error instanceof ERC8126Error) throw error;
    throw new ERC8126Error(0x07, `Metadata resolution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

async function ETV(m: AgentMetadata, c: VerificationProviderConfig): Promise<VerificationResult> {
  return {
    type: 'ETV',
    status: VerificationStatus.Passed,
    score: 25,
    proofId: generateProofId('ETV', m.contractAddress || ''),
  };
}

async function MCV(m: AgentMetadata, c: VerificationProviderConfig): Promise<VerificationResult> {
  return {
    type: 'MCV',
    status: VerificationStatus.Passed,
    score: 30,
    proofId: generateProofId('MCV', m.imageUrl || ''),
  };
}

async function SCV(m: AgentMetadata, c: VerificationProviderConfig): Promise<VerificationResult> {
  return {
    type: 'SCV',
    status: VerificationStatus.Passed,
    score: 30,
    proofId: generateProofId('SCV', m.solidityCode || ''),
  };
}

async function WAV(m: AgentMetadata): Promise<VerificationResult> {
  return {
    type: 'WAV',
    status: VerificationStatus.Passed,
    score: 15,
    proofId: generateProofId('WAV', m.url || ''),
  };
}

async function WV(m: AgentMetadata): Promise<VerificationResult> {
  return {
    type: 'WV',
    status: VerificationStatus.Passed,
    score: 20,
    proofId: generateProofId('WV', m.walletAddress || ''),
  };
}

function calculateOverallRiskScore(scores: number[]): number {
  const valid = scores.filter((s) => s >= 0 && s <= 100);
  return valid.length ? Math.round(valid.reduce((a, b) => a + b, 0) / valid.length) : 0;
}

function getRiskTier(score: number): RiskTier {
  if (score <= 20) return RiskTier.Low;
  if (score <= 40) return RiskTier.Moderate;
  if (score <= 60) return RiskTier.Elevated;
  if (score <= 80) return RiskTier.HighRisk;
  return RiskTier.Critical;
}

function generatePDVProof(result: any): string {
  return '0x' + crypto.createHash('sha256').update(JSON.stringify(result) + Date.now().toString()).digest('hex');
}

async function QCV(data: any) {
  return {
    recordId: '0x' + crypto.createHash('sha256').update(Date.now().toString()).digest('hex'),
    algorithm: 'AES-256-GCM',
  };
}

export async function verifyAgent(agentId: bigint, config: VerificationProviderConfig) {
  const metadata = await resolveAgentMetadata(agentId, config);

  const [etv, mcv, scv, wav, wv] = await Promise.all([
    ETV(metadata, config),
    MCV(metadata, config),
    SCV(metadata, config),
    WAV(metadata),
    WV(metadata),
  ]);

  const overallRiskScore = calculateOverallRiskScore([etv.score, mcv.score, scv.score, wav.score, wv.score]);
  const riskTier = getRiskTier(overallRiskScore);
  const pdvProofId = generatePDVProof({ etv, mcv, scv, wav, wv, overallRiskScore, agentId: agentId.toString() });

  const qcvRecord = await QCV({ overallRiskScore, pdvProofId });

  const validationRecord = config.validationRegistry
    ? await submitToValidationRegistry(agentId, overallRiskScore, pdvProofId, config)
    : null;

  return {
    agentId,
    overallRiskScore,
    riskTier,
    etv,
    mcv,
    scv,
    wav,
    wv,
    pdvProofId,
    qcvRecord,
    validationRecord,
    verifiedAt: new Date().toISOString(),
  };
}

async function submitToValidationRegistry(
  agentId: bigint,
  score: number,
  pdvProofId: string,
  config: VerificationProviderConfig
) {
  return pdvProofId;
}

function generateProofId(type: string, data: string): string {
  const input = `${type}:${data}:${Date.now()}`;
  return '0x' + crypto.createHash('sha256').update(input).digest('hex');
}

export { verifyAgent };

Security Considerations

Verification Trust

Users should consider that verification through this standard indicates the agent has passed specific technical checks at a point in time, but does not guarantee the agent's future behavior or intentions. Risk scores provide guidance, but users should exercise their own judgment.

Wallet Security

Agents must ensure that their registered wallet addresses are secure. Compromise of a wallet could allow an attacker to impersonate a legitimate agent. Re-verification is available to update risk scores.

URL Hijacking

If an agent's URL is compromised after registration, the attacker could serve malicious content. Users should consider verifying agents' current status before interacting with them. WAV re-verification can detect compromised endpoints.

Smart Contract Risks

For agents with registered contract addresses, standard smart contract security considerations apply. ETV and SCV provide initial verification, but users should consider auditing any contracts they interact with.

ZKP Security

PDV implementations SHOULD use established ZKP systems with proven security properties:

Quantum Computing Threats

Current cryptographic primitives face potential threats from quantum computing:

Provider Trust

Users must evaluate their trust in the verification providers they choose. Different providers may have varying levels of thoroughness, independence, and reliability. ZKPs generated by PDV provide verifiable evidence of verification completion that can be independently validated.

Attack Vectors

Dependency on ERC-8004

Reliance on ERC-8004 registries introduces a dependency risk; implementations must use the canonical deployed addresses and verify the integrity of tokenURIs.

Copyright

Copyright and related rights waived via CC0.