[DISCUSSION] ERC: MultiTrust Credential (MTC) — Core & ZK Proof (optional)

Hello everyone,

We are proposing a minimal on-chain anchor for VC-aligned reputation credentials (MTC Core) and an optional ZK presentation interface (MTC-ZK) with a fixed Groth16 ABI—enabling privacy-preserving, interoperable eligibility checks (e.g., score ≥ 80, violations ≤ 2). We are seeking community feedback on the initial draft.

Problem & Motivation

dApps need to evaluate user reputation or eligibility across apps without revealing raw data. Today’s approaches are bespoke or SBT-centric, fragmenting semantics and making revocation and consistency difficult.

MTC standardizes issuing/updating/revoking a non-transferable credential and verifying only the predicate (not the raw value) via a fixed ZK ABI, so wallets/SDKs/dApps can check the same thing the same way.

Use cases

A. Learning: “Reward NFT for score ≥ 80”

  • A platform issues an examScore metric to the student’s address via MTC (on-chain stores only a commitment; the actual score remains off-chain).
  • The student presents a ZK proof for score ≥ 80; no raw score is disclosed.
  • A rewards contract calls proveMetric(...)true ⇒ mints a “Pass” NFT.
  • If cheating is later found, the issuer revokes the metric; subsequent claims fail automatically.

Benefits: Show only “qualified,” reuse the same predicate across apps, immediate and auditable revocation.

B. Community/Mobility: “VIP event for violations ≤ 2”

  • The operator tracks violationPoints on MTC; policy (LTE) is fixed via CompareMask (GTE/LTE/EQ, inclusive) and may be frozen.
  • Users prove violations ≤ 2 with ZK for entry; violation details remain private.
  • Staff updates/penalizes via updateMetric/slash; rule changes are governed and logged.

Benefits: User privacy; consistent policy and instant revocation; transparent audit trail.

Specification (at a glance)

MTC Core (ERC category)

  • Schema: registerMetric(metricId, role, mask)
  • Write: mint / mintBatch / updateMetric / updateMetricBatch / revokeMetric / slash
  • Read: getMetric(tokenId, metricId), tokenIdOf(address)
  • Non-transferable & one token per subject: MUST
  • CompareMask: GTE=1, LTE=2, EQ=4 (inclusive); after freeze, setCompareMask MUST revert
  • Events: MetricRegistered / MetricUpdated / MetricRevoked / Slash / CompareMaskChanged / MaskFrozenSet
  • ERC-165: MUST implement and expose interfaceId

MTC-ZK (optional)

  • proveMetric(a,b,c,publicSignals) with fixed order [mode, root, nullifier, addr, threshold, leaf]
  • Binding: root == leafFull (current Core anchor), tokenId == tokenIdOf(address(uint160(addr)))
  • Policy: mode must be allowed by Core mask; mask mismatch and mode==0 MUST revert
  • Domain separation (in circuit):
    treeLeaf = Poseidon(leaf, addr, keccak256(abi.encode(chainid(), address(this))))
  • Optional events: VerifierSet, ProofVerified

Why MTC (design benefits)

  • Privacy × Interop: Predicate-only proofs; one stable ABI across wallets/dApps
  • Instant revocation: revokeMetric makes future claims fail by construction
  • Policy consistency: CompareMask (+ freeze) avoids ad-hoc rule changes
  • One per subject, non-transferable: Prevents lending/marketplaces
  • Replay-safe: Bound to Core’s current anchor and a domain-separated leaf

Related ERCs — Differences at a Glance

Aspect MTC (proposed) ERC-725/735 ERC-4973 ERC-5192
Goal / Scope VC-aligned reputation metrics on a non-transferable credential; issue / update / revoke; verify predicates only via ZK 725: identity registry; 735: claims model Account-bound token (ABT) Minimal SBT (lock state only)
Representation Non-transferable credential + metric (value kept as commitment) Identity / claims registry (may contain PII) Non-transferable token Non-transferable token
Transferability MUST NOT transfer; one token per subject (MUST) N/A Non-transferable Non-transferable
On-chain data Commitment + timestamps; PII stays off-chain Claims (content depends on app; may include PII) Token ownership Token ID + lock state
Verification Fixed ZK ABI checks predicate only (e.g., score ≥ threshold) Claim validity / signatures Ownership ≈ eligibility Locked ≈ eligibility
Revocation revokeMetricimmediate invalidation (later proofs fail) Claim revocation (app-specific) Up to issuer (out of scope) Minimal (lock/unlock)
Policy control CompareMask (GTE/LTE/EQ, inclusive) + freeze (no further changes) Out of scope Out of scope Out of scope
ZK Yes (optional): proveMetric(a,b,c,publicSignals) with fixed order Not specified Not specified Not specified
Replay resistance Current Core anchor (root == leafFull) + domain-separated leaf (chainId + contract) Impl-specific Impl-specific Impl-specific
ERC-165 Required (Core & ZK) Impl-specific Yes Yes
Typical use Threshold checks (scores/violations), reward NFTs, gated entry KYC/attribute claims storage & presentation Achievement badges, memberships Minimal “present/issued” signal
Composability Use MTC to decide, then mint 4973/5192 tokens as badges Can back MTC via off-chain VC layer Use MTC as pre-check; mint ABT on success Use MTC as pre-check; minimal SBT for display

TL;DR: MTC standardizes predicate verification (not raw values) with ZK.
725/735 = claim/identity layer; 4973/5192 = token representations. MTC sits upstream as a shared, privacy-preserving decision layer and composes well with them.

Draft EIPs (EIP-1 compliant)

I haven’t made the PR yet. I’d like to proceed based on everyone’s feedback.

Reference implementation (non-normative)

Contracts: MultiTrustCredential.sol


As this is our initial draft, I’d greatly appreciate broad feedback—on terminology, spec clarity, and interop. Suggestions and alternatives are welcome.

1 Like