ERC-8004 Proof-of-Human
An optional extension to ERC-8004 that adds on-chain, privacy-preserving proof-of-human verification for AI agents, proposed as a new section in the EIP, similar to how ERC-721 defines optional Metadata and Enumerable extensions.
What is ERC-8004?
ERC-8004 is a proposed standard for on-chain AI agent registries. It defines a minimal interface for registering agents, assigning them unique IDs (as NFTs), and looking up agent ownership. Think of it as ENS for AI agents: a universal, composable identity layer.
1/// @title IERC8004 - Agent Registry (Base Standard)2/// @notice Minimal interface for on-chain agent registration3interface IERC8004 {4 /// @notice Register a new agent with a public key5 function registerAgent(bytes32 agentPubKey) external returns (uint256 agentId);67 /// @notice Look up an agent's ID by public key8 function getAgentId(bytes32 agentPubKey) external view returns (uint256);910 /// @notice Get the owner of an agent (ERC-721)11 function ownerOf(uint256 agentId) external view returns (address);12}
The base standard is intentionally minimal. It doesn't specify how agents are verified or who operates them. That's where optional extensions come in.
The Problem
ERC-8004 registers agents, but it doesn't answer the critical question: “Is this agent operated by a real human?”
Without proof-of-human, anyone can register unlimited agents, enabling sybil attacks, bot farms, and impersonation. Protocols that gate access to “verified agents” have no standard way to check humanity. Each project builds its own solution, fragmenting the ecosystem and creating integration overhead.
Our Proposal
We propose IERC8004ProofOfHuman, an optional extension interface that adds proof-of-human verification as a first-class, composable property of agent identity. Registries that need human verification implement this alongside the base standard. Three design principles:
Provider-Agnostic
Any ZK identity system (Self Protocol, World ID, Humanity Protocol) can implement IHumanProofProvider. The registry doesn't care how humanity is proven.
Sybil-Resistant
Each human produces a unique, scoped nullifier. The registry tracks agent counts per nullifier. Services choose their own limits (1, N, or unlimited).
Privacy-Preserving
Only a nullifier is stored on-chain. No name, no passport number, no biometrics. ZK proofs verify humanity without revealing identity.
The Interface
IERC8004ProofOfHuman
proposed extensionExtends ERC-8004 with human verification, sybil detection, and provider management. Registries opt in by implementing this interface alongside the base standard.
1/// @title IERC8004ProofOfHuman2/// @notice Optional extension to ERC-8004 adding proof-of-human verification3interface IERC8004ProofOfHuman is IERC8004 {4 // ── Registration ──────────────────────────────────────5 /// @notice Register an agent with verifiable proof-of-human6 function registerWithHumanProof(7 string calldata agentURI,8 address proofProvider,9 bytes calldata proof,10 bytes calldata providerData11 ) external returns (uint256 agentId);1213 /// @notice Revoke an agent's human proof (same nullifier required)14 function revokeHumanProof(15 uint256 agentId,16 address proofProvider,17 bytes calldata proof,18 bytes calldata providerData19 ) external;2021 // ── Verification (read by any service/contract) ──────22 /// @notice Check if an agent has verified proof-of-human23 function hasHumanProof(uint256 agentId) external view returns (bool);2425 /// @notice Get the nullifier for an agent26 function getHumanNullifier(uint256 agentId) external view returns (uint256);2728 /// @notice Get which provider verified this agent29 function getProofProvider(uint256 agentId) external view returns (address);3031 // ── Sybil detection ──────────────────────────────────32 /// @notice Count active agents for a human (by nullifier)33 function getAgentCountForHuman(uint256 nullifier) external view returns (uint256);3435 /// @notice Check if two agents are backed by the same human36 function sameHuman(uint256 a, uint256 b) external view returns (bool);3738 // ── Provider management ──────────────────────────────39 /// @notice Check if a proof provider is whitelisted40 function isApprovedProvider(address provider) external view returns (bool);41}
IHumanProofProvider
proposed extensionPluggable interface for identity verification backends. Any ZK identity system can implement this to serve as a proof provider.
1/// @title IHumanProofProvider2/// @notice Pluggable identity backend for proof-of-human3interface IHumanProofProvider {4 /// @notice Verify a ZK proof and return (success, nullifier)5 /// @dev The nullifier must be deterministic: same human + same scope6 /// always produces the same nullifier.7 function verifyHumanProof(8 bytes calldata proof,9 bytes calldata data10 ) external returns (bool verified, uint256 nullifier);1112 /// @notice Human-readable provider name (e.g. "Self Protocol")13 function providerName() external view returns (string memory);1415 /// @notice Verification strength score (0-100)16 /// @dev 100 = passport/NFC chip, 60 = government ID, 40 = liveness check17 function verificationStrength() external view returns (uint8);18}
Why Standardize This?
Composability
Any protocol can check hasHumanProof() or sameHuman() with a single contract call. No custom integrations needed.
Provider competition
Multiple identity providers can compete on verification quality. Services choose which providers they trust via the whitelist.
Future-proof
New ZK identity systems can plug in by implementing IHumanProofProvider. The extension interface stays stable.
Interoperability
Agent identities are portable across chains and applications. The sameHuman() check enables cross-protocol reputation.
Full ERC-8004 Provider Coverage
ERC-8004 defines three registry types. Self Agent ID implements all three as on-chain contracts:
SelfAgentRegistry
Agent NFT minting, human proof storage, ZK-attested credentials, and metadata (A2A Agent Cards).
SelfReputationProvider
Reads verificationStrength() from the proof provider. Supports batch queries across multiple agents.
SelfValidationProvider
Real-time proof validation with configurable freshness threshold (default: ~1 year).
Agent Cards as agentURI
A2A Agent Cards are stored on-chain in agentMetadata. A stateless API reads the blockchain and serves the data as HTTP JSON. That URL becomes the agent's agentURI in ERC-8004.
GET /api/cards/{chainId}/{agentId} → Agent Card JSON
GET /api/reputation/{chainId}/{agentId} → { score, proofType }
GET /.well-known/a2a/{agentId}?chain={chainId} → Redirect to card resolverFor fully on-chain contexts, the SDK generates data:application/json;base64,... URIs.
Reference Implementation
We've built a complete reference implementation using Self Protocol as the proof provider, deployed on Celo. It supports four registration modes (verified wallet, agent identity, wallet-free, and passkey smart wallet) with full sybil resistance and ZK privacy.
EIP Proposal
Pull Request: Coming Soon
We're preparing a PR to the ERC-8004 EIP document proposing proof-of-human as an optional extension section, similar to how ERC-721 defines optional Metadata and Enumerable extensions within the same EIP. The PR will include the full interface specification, rationale, security considerations, and a link to our reference implementation.
PR link will be added here