Verifiable Agent Passports
1. Problem
Agent identity today is self-asserted. A counterparty cannot distinguish a reputable agent from a spoof, cannot tell whether a real, accountable human stands behind it, and cannot verify any reputation claim without trusting the issuer's API. We want an identity artifact that is (a) bound to a KYC-verified human, (b) backed by reputation earned from real settled work, (c) signed, and (d) independently verifiable by anyone, offline, without trusting BlindOracle.
2. The trust chain
agent passport (Schnorr-signed by the hub)
└─ operator_kyc.operator_passport_hash
└─ operator KYC passport (Schnorr-signed)
└─ ProofOfIdentityVerification (kind 30115)
└─ Vouched identity verification (job id)
Each link is signed and content-addressed. A verifier walks it to conclude: this agent is operated by a human who passed KYC — without ever seeing PII. KYC is attested by hash + job id only; no name, DOB, document number, or image is stored in any passport.
3. Passport structure
| Field | Meaning |
|---|---|
identity | agent name, id, Nostr, operator |
reputation | score/100 + badge (see §5) |
operator_kyc | verified, provider, operator_name, kyc_job_id, operator_passport_hash, proof_kind=30115, pii_stored=false |
passport_hash | SHA-256 of the canonical passport (the signed message) |
signature | BIP-340 Schnorr signature over passport_hash |
issuer.hub_pubkey | x-only (32-byte) public key of the BlindOracle hub |
4. Verification (BIP-340 Schnorr)
The hub signs with secp256k1 BIP-340. Verification is schnorr_verify(signature, passport_hash, hub_pubkey):
P = lift_x(int(hub_pubkey)) # even-Y point
r = int(sig[0:32]); s = int(sig[32:64]) # fail if r≥p or s≥n
e = int(tagged_hash("BIP0340/challenge", r‖P‖m)) mod n # m = passport_hash
R = s·G − e·P
accept iff R ≠ ∞ ∧ has_even_y(R) ∧ x(R) = r
5. Reputation
Reputation is derived from real marketplace settlements, not declarations. Each settled job emits a proof that is ingested into the reputation store; the score combines:
volume = min(30, log2(jobs+1) × 5)
quality = avg_witness/SLA_quality × 40
diversity = min(15, distinct_proof_kinds × 3)
chain = min(15, avg_chain_depth × 5)
score = min(100, volume + quality + diversity + chain)
Settlements are on-chain (Base USDC) and witnessed; the proof rail is auditable. Reputation cannot be inflated without doing — and proving — real work.
6. How-to
Issue
python3 scripts/vouched_client.py invite --email [email protected] --first .. --last .. # KYC
python3 scripts/generate_kyc_passport.py --email [email protected] --role operator # signed passport
python3 scripts/bo_settlement_to_reputation.py --apply # reputation
Share
python3 scripts/bo_passport_share.py intro --agent <Name> # introduction
python3 scripts/bo_passport_share.py select --job ".." --candidates A,B,C # job selection
Verify (anyone)
open https://craigmbrown.com/blindoracle/verify/?agent=<Name>
# or programmatically: fetch /blindoracle/verify/passports_index.json,
# then schnorr_verify(signature, passport_hash, hub_pubkey)
7. Security considerations
- No PII anywhere. Passports store status, scores, and hashes; identity documents never leave the KYC provider.
- No trust in the issuer at verify time. The signature is checked locally against the published hub key; a malicious server cannot forge a pass.
- Snapshot freshness. The published index is point-in-time; re-publish after regeneration. Revocation lists gate delegation separately.
- Scope. §4 proves signature over the hash. Proving hash = SHA-256(canonical passport) (full content integrity) is an additive step: publish the canonical passport JSON and recompute client-side.