Assigned ERC-8419 (2026-09-20). Latest: revision 4 — see the replies below; current Sepolia addresses are in the repo README.
PR: ethereum/ERCs#2012 · Repo / reference implementation: garyyang-finchip/kya-standard · Status: Draft, ERC-8419
What this proposes
ERC-8004 gives agents portable identity and a place to accumulate raw trust signals (Reputation, Validation). It deliberately stops short of trust conclusions — a shared way to say “this agent was checked under principle X, by issuer Y, reached level L, valid until T, not revoked.”
This ERC standardises the container for such conclusions, not the conclusions themselves:

- Scheme Registry — registers a KYA Scheme: an addressable, versioned, freezable pointer to a descriptor that says what is checked, how the result is expressed as a
uint8 level, which evidence kinds are admissible, and how assertions are admitted (ATTESTEDby an issuer, orPROVEDby a verifier contract). - KYA Registry — records Assertions
(subjectKey, schemeId, issuer, level, claimDigest, issuedAt, expiresAt, evidenceHash, status)with per-issuer supersession and revocation, and resolves them:resolve(subject, schemeId, issuers[])/check(subject, schemeId, minLevel, issuers[]).issuersmust be non-empty — same Sybil rationale as 8004’sgetSummaryrequiringclientAddresses. - ZK-KYA profile — not a second registry.
attestWithProof(subject, schemeId, publicInputs, proof)calls the scheme’sIKYAVerifier, which returns(ok, subjectKey, nullifier, level, claimDigest, expiresAt). The registry enforces subject binding and nullifier consumption and records the assertion withissuer = verifier. Any proving system enters via an adapter; the spec fixes only the public-input layout (kya-public-v1). Proofs can also be presented ephemerally in the handshake without ever touching the chain.

- Handshake — EIP-712
KYAChallenge/KYAPresentation,/.well-known/kya.jsondiscovery; mutual KYA is two exchanges.

- Policy (minimal) —
registerPolicy(uri, hash)gives relying-party requirements an id that can be named in a challenge; on-chain evaluation is optional. - ERC-8004 binding —
erc8004is the MUST-support subject type(chainId, identityRegistry, agentId). OptionalsupportedTrust: ["kya","zk-kya"], aKYAservices entry, a"kya"metadata key, and a KYA Bridge that acts as an 8004 validator and mirrors levels to 0–100 undertag = "kya:<8 hex of schemeId>", so 8004-only clients see KYA outcomes with zero changes to 8004.
The framework never defines a KYA algorithm or a credit rule. That is the point: like 8004 with reputation math, fixing rules on-chain would be obsolete before Final; a container for rules is not.
What is in the repo
Full ERC text; reference contracts (KYASchemeRegistry, KYARegistry, KYAPolicyRegistry, KYABridge8004, a Groth16→IKYAVerifier adapter); JSON Schemas for scheme / policy / discovery documents; deterministic vectors (ids, EIP-712 digests, ERC-165 ids); a 17-case end-to-end suite on an in-process EVM covering attested and proved flows, revocation/expiry, policy evaluation and the full 8004 bridge round-trip.
Where I would most like feedback
- Subject abstraction — is
(subjectType, subjectData)witherc8004as MUST andaccount/erc721/didas optional the right cut, or should v1 be 8004-only? - Verifier-as-issuer in proved mode — relying parties trust a verifier address the same way they trust an attester. Is that vocabulary acceptable, or should proved assertions carry a separate
verifierfield? - Bridge design — a curated validator with operator-configured issuers and level→0–100 map, deterministic
requestHashbound to(agentId, schemeId). Is mirroring into Validation (not Reputation) the right choice? - Nullifier scoping —
schemevsscheme-epoch; should domain separation (chainId + registry) be MUST rather than SHOULD? - Relationship to ERC-8143 and to generic attestation services — this draft positions itself as the agent-KYA semantic layer that can sit on top of either. Push back welcome.
Prior work from the same author: ERC-8338 (Token-Bound Executable Skills), ERC-8414 (Token-Bound Task Tenders). Those appear here only as informative use cases; nothing in this ERC depends on them.
Update: revision 2 of the draft after an external design review, plus a live Sepolia reference deployment
Since the OP we had the whole design reviewed with an adversarial eye. Several points were right and are now in the text and the reference implementation (PR updated in place; the kya-standard repo is in sync). The short version of what changed, and why:
What the framework is (and is not). KYA is a registry for trust conclusions about agents — not an identity system, not a reputation score, not an anonymity layer. Each conclusion is addressed by a scheme whose semantics are now immutable per schemeId (only the descriptor URI can be re-pointed; any semantic change is a new scheme with predecessor). Every scheme declares what it binds to — the identity record, the current controller, or a specific instance — because an ERC-8004 agent is a transferable ERC-721 and “this agent is accountable” does not automatically survive a sale. Relying parties get a rule they can implement (check for transfers since issuedAt); the registry stays ignorant of ERC-721 mechanics.
level is still a uint8, but ordering is now a profile. resolve’s “highest wins”, check’s minLevel and the bridge’s responseMap all assume a total order. That assumption is isolated as the Ordered-Level Profile (result.kind = "ordered-level"); pass/fail and categorical results use level as a code or leave it 0 with the result committed in claimDigest.
ZK-KYA, stated precisely. The profile hides the fact issuer and the underlying facts. It does not hide the subject — subjectKey is public — and we no longer describe it as anonymous. Two roles are now explicit: the fact issuer (attestor, never named on-chain) and the admitting verifier (recorded as issuer); the assertion carries an anchor (for the reference circuit, the issuer-set root) so relying parties pin (verifier, anchor) rather than an address alone. Three concrete fixes came out of the review:
- the attestor’s credential now includes
schemeId, and the circuit constrains it to the adapter’s argument — otherwise a credential issued under a lenient scheme was presentable under a strict one that shares attestors (cross-scheme replay); - the epoch is enforced on-chain from
block.timestamp(current − grace ≤ epoch ≤ current), not supplied by the prover — otherwise “re-prove per epoch” was “mint a fresh nullifier at will”; - the 256-bit → (hi, lo) split uses an alias-checked decomposition, so a nullifier has exactly one encoding.
Bridge. Explicitly an optional, lossy snapshot of the KYA Registry: requestHash now includes the bridge address, a level outside the response map makes sync revert instead of guessing upward, and the text says plainly that a transfer after sync leaves a stale mirror until someone re-syncs.
Handshake. Acceptance rules are normative now (single-use challenge, presented assertions must belong to the challenge’s schemeIds, policy decides partial satisfaction, empty presentation only satisfies an empty challenge). The policy interface is split into a required base and an optional on-chain evaluator, discoverable via ERC-165.
Sepolia (revision 2), against the official ERC-8004 IdentityRegistry 0x8004A818…BD9e, agentId 10387
| contract | address |
|---|---|
| KYASchemeRegistry | 0xAc7B642a5760467178F20c984f02cc72CCCa8E3f |
| KYARegistry | 0xeBf357c87639aCcC0DaA505fAAf3F6E9b079AB9f |
| KYAPolicyRegistry | 0x9B53BAD4346AacB34Bac328F1d856dfa2F246cfF |
| ValidationRegistry8004 (spec-conforming stand-in; canonical one not yet deployed) | 0x4aD87d7D55C753c53A801ca9a23495fb4f9bAd53 |
| KYABridge8004 | 0xCcd683927d1fC03A0163B3e9FbE7fC44afFbA5e4 |
| Groth16Verifier (circuit rev 2, test ceremony) | 0xBaE26c2a9b23c37Da76c4905F9F09004dFDBc7a9 |
| Groth16KYAVerifierAdapter (30-day epochs, grace 1, pinned issuer-set root) | 0xbC2E1A0FF358B64288a7D4157B996C72b6Ad44cD |
Worked examples, every one read back from chain: setMetadata(10387, "kya", …) on the official registry (tx) · attested scheme, attest(level 2) → check(≥2) true (tx) · attestWithProof with a real Groth16 proof (scheme-bound credential, epoch 690 enforced by the adapter, recorded anchor = the pinned issuer-set root; which of the three demo attestors signed is not recoverable on-chain) → check(≥4, [adapter]) true (tx) · policy allOf[attested ≥ 2, proved ≥ 4], evaluate() true (tx) · ERC-8004 bridge: agent owner files validationRequest with the deterministic requestHash, anyone calls sync, Validation Registry reports 60/100 under tag kya:3673f050, getSummary(10387, [bridge], tag) → count 1 / average 60 — request tx · sync tx
Everything — tx hashes, the proof, public signals, descriptors, and the superseded revision-1 deployment for the record — is in deployments/ of garyyang-finchip/kya-standard. npm test runs 18 end-to-end cases on an in-process EVM; npm run test:zk runs 14 more with the real circuit, including the adversarial ones (prover-chosen future/stale epoch, cross-scheme replay, tampered signals, aliased encodings, attestor outside the pinned set). The Groth16 keys are a single-party test ceremony and say so everywhere.
Two things we would still like input on: whether binding should be a per-scheme declaration (current) or a per-assertion field, and whether the epoch window rule belongs in the ERC text as MUST for every epoch-scoped scheme (current) or should be left to the verifier’s descriptor.
Clarification: the ZK profile covers two usage patterns, and the text now says so
Re-reading the draft, §5 described ZK-KYA as if every proved scheme were a credential: a hidden fact issuer signs a verdict in advance, and the proof transports it privately. That is what the reference circuit does (hence issuerSetRoot, anchor, issuerPolicy: verifier-only), but it is one usage, not the definition. Three things have been clarified in the PR, interfaces unchanged:
-
Predicate pattern added (§5.1, informative). The scheme can be the decision rule: a relying party (or a community agreeing an underwriting standard) publishes its rule as a circuit or zkVM program and deploys the verifier; the counterparty evaluates the rule over its own authenticated private data inside the proof and presents only the verdict. No third party issues a credit verdict beforehand, and the relying party is never sent the raw data. The two patterns combine — one circuit can check source-signed data and evaluate the rule over it. The section is explicit about what this does not give you: the protocol does not destroy data or verify that anyone deletes proofs; inputs must be authenticated (storage/receipt proofs against a block hash, zkTLS-style notarised transcripts, or source-signed data, in decreasing order of trustlessness, with
anchorcommitting to the source); and authenticity is not completeness, so a verdict is “satisfies rule P over the named sources, window and coverage”, never an unqualified “is creditworthy”. -
Scope of the scheme-binding MUST narrowed. The draft required that “whatever the fact issuer signs” include the
schemeId. That is right for a signed object that carries a pre-made verdict — it is what stops a level issued under a lenient scheme being presented under a strict one — but wrong for signed inputs (a bank statement, an exchange export) that carry no verdict and legitimately predate any scheme. The rule now reads: the proof’s statement MUST be bound to the verifier’sschemeId(adapters feed it as a public input); additionally, verdict-carrying credentials MUST embed it. Signed inputs are exempt from the second half; their binding to the rule is the computation itself. This is a semantic clarification with no ABI change, but it does change the applicability of a MUST, so flagging it rather than calling it editorial. -
issuerin PROVED mode restated. It identifies the admitting verifier — which verification logic accepted the proof — not the source of the facts and not a guarantor. What stands behind the verifier differs by pattern and is whatanchorcommits to (attestor set in the credential pattern; block hash / notary set / data-signer set in the predicate pattern). Relying parties pin(verifier, anchor).
Also added to Security Considerations: query composition. A zero-knowledge proof bounds what one answer reveals, not what a sequence reveals (“above 100? above 50? above 75?” recovers a balance from perfectly ZK answers). The prover’s disclosure decision is the scheme’s outputs, parameters and query shape, and the set of schemes it will answer for one counterparty — not the proof system — and an audit of an immutable scheme is a judgement at a point in time, not a permanent one.
What has not changed and is not claimed: the reference circuit still demonstrates only the credential pattern; there is no predicate-pattern circuit yet; and there is no mechanism for a relying party to ship an ad-hoc rule inside a challenge. That last one is noted as a future extension — it needs a binding among request, program, parameters and data scope (a program hash alone is insufficient), and adding a member to KYAChallenge changes its EIP-712 type hash, so it would be a new message type or versioned extension rather than a compatible edit. Views on whether that belongs in this draft or a follow-up are welcome.
