Everything in this course converges here: prove you're old enough, solvent enough, citizen enough — enough being the operative word. Selective disclosure is zero knowledge doing paperwork: reveal the predicate, hide the data.
The oversharing crisis
To buy a beer you prove you're over 18. The tool: hand over your entire identity — name, exact birthdate, address, document number, signature, sometimes your photo gets scanned and stored. The bouncer needed one bit; he received everything. Multiply by every bar, website, rental car desk and crypto exchange, and you get a permanent trail of identity dumps waiting to be breached, sold, or subpoenaed.
What we actually want is a predicate proof: convince the verifier that some statement about your attributes is true, while the attributes themselves stay in your pocket.
Verifier wants to know…
Predicate
What you keep private
"old enough to enter"
age ≥ 18
birth date, name, address
"EU resident"
country ∈ EU_SET
which country exactly
"can afford this loan"
salary ≥ k
exact salary, employer
"account in good standing"
status = active ∧ expiry > today
account number, history
"human, one-per-person"
holds valid passport credential
passport number, nationality, name
🧪 The Bouncer: two ways to prove your age
Same club, same night, same you — two different technologies. Watch what the club (and its CCTV partner, and its data broker) actually captures.
🪪Nightclub Verifier — ID card vs ZK credential
Your credential (on your phone)
name
Aiko Tanaka
birthdate
1999-04-17
address
12 Rue Oberkampf, Paris
citizenship
Japan
doc number
XN4471982
issuer: 🏛️ GovID — signed, tamper-proof
📷 What the club captured tonight
nothing yet…
> bouncer online. state your proof method…
The triangle: issuer · holder · verifier
The magic of step 2: the proof convinces the verifier that (a) a valid issuer signed the underlying attributes, (b) the attributes satisfy the predicate — all without opening the envelope. The issuer can be offline forever; the verifier needs only the issuer's public key. This triangle is exactly how AnonCreds (Hyperledger), BBS+ credentials (W3C), and the EU's digital identity wallets work.
🔍 Deeper dive · unlinkability — the metadata war
Even a perfect zero-knowledge proof leaks metadata: when, from where, and the fact you proved something at all. Worse, presentations can correlate — if every proof embeds the same unique credential serial, two verifiers can compare notes and reconstruct your evening ("wallet #4471 entered a bar at 22:14, bought wine at 22:51, booked a hotel at 23:30"). The defenses are structural: derived proofs (BBS+ presentations are statistically unlinkable across verifiers) and pairwise link secrets (AnonCreds gives each relationship its own pseudonym). The tension is permanent — revocation and audit want stable handles, privacy wants disposable ones — and real systems navigate it explicitly. Rule of thumb: a predicate proof is only as private as the set it hides you in.
How "age ≥ 18" becomes math: sets and trees
A clean way to prove a range without revealing the value: the issuer publishes a Merkle tree of approved values — one leaf per allowed age, root signed. Your proof: "I hold a path through this tree for some leaf." A plain Merkle path reveals which leaf (the value itself); a ZK membership proof shows the path validates without showing it. Chapter 3's hashes + Chapter 5's commitments + Chapter 6's algebra, assembled:
🌲Merkle Membership — the approved-ages tree (18…25)
your age:root = …
> pick an age and present a proof…
The subtlety you just saw
In plain reveal mode the verifier learns your exact age (the leaf must be shown to re-hash the path). In ZK mode the same tree backs a zero-knowledge membership proof: the verifier learns age ∈ {18,…,25} → TRUE and nothing else — not which leaf, not your age, not even a per-visit identifier. Real systems (AnonCreds) use the same shape with hidden-linkability accumulators instead of a visible tree.
🔍 Deeper dive · revocation without doxxing
Credentials expire or get revoked, and checking "still valid?" naively means asking the issuer about your credential — instant tracking. The classic fix is a cryptographic accumulator: one small number that summarizes an entire set, with (non-)membership proofs that don't reveal which element you hold. The issuer adds revoked IDs to the accumulator; unrevoked holders carry an update "witness" and prove "not in that set" in zero knowledge at each presentation. It's exactly the Merkle-membership game you just played, upgraded to hide the leaf and support cheap updates as the set evolves. (Smaller sets — the EU list, the 18+ range — work fine as plain signed Merkle roots; accumulators earn their keep on millions of credentials.)
🧪 Predicate Console
You hold one credential with six attributes. Choose what the verifier demands, run the session, and audit exactly what crossed the line. Redacted bars = never transmitted, not even hashed-then-guessed.
🎛️Predicate Console — you control the disclosureleak score: 0 attributes
your wallet's view — what was sent
> verifier terminal ready…\n> select a predicate and RUN
🔍 Deeper dive · replay attacks & holder binding
A proof that convinced the bar must not convince a data broker who recorded it. Two standard stitches, both built from your Chapter 6 toolkit. First, freshness: the verifier issues a random nonce and the proof consumes it (Fiat–Shamir over the nonce) — a recorded proof hashes a stale nonce and fails instantly. Second, holder binding: the credential is issued to a key on your device, and every proof attests "the presenter holds the private key that owns this credential" — a Schnorr-style ID proof embedded in the predicate proof. Together they say: only you, only now. A stolen wallet file without the key is dead paper; a recording without a live nonce is history.
Where this ships today
AnonCreds (Hyperledger Indy/Aries) — the oldest production lineage: CL-signature credentials with built-in predicate proofs (age ≥ n, set membership) and revocation via cryptographic accumulators.
BBS+ signatures (W3C Verifiable Credentials, IETF SD-JWT's cryptographic cousin) — issue once, derive per-presentation proofs revealing chosen attributes; the signature itself is proven in ZK.
SD-JWT — selective disclosure via salted hashes: simpler, not fully ZK (issuer still sees what it signed; holder picks subsets).
EU Digital Identity Wallet (eIDAS 2.0, rolling out ~2026) — regulatory selective disclosure for 450M citizens: prove attributes of government-issued IDs without showing documents.
Passport ZK (Anon Aadhaar, Rarimo/ZeroID, OpenPassport, zkPassport) — prove "valid passport, age ≥ 18, not sanctioned" to smart contracts via NFC-chip signatures verified inside a SNARK.
Private DeFi — prove solvency or accreditation without portfolio doxxing.
🔍 Deeper dive · choosing your disclosure architecture
If you're picking a stack for a product, the trade space reduces to three families:
Architecture
Issuer effort
Unlinkable?
Holder cost
Ships as
Full-ZK credentials (AnonCreds, BBS+)
new credential infra
yes — derived/pairwise proofs
milliseconds
Hyperledger Aries, W3C VC + BBS+
SD-JWT
minimal — any JWT issuer
no — colluding verifiers link sessions
trivial
IETF draft, OpenID ecosystems
SNARK over documents
none — reuse existing signatures
yes
seconds (phone-class)
passport ZK, anon Aadhaar
The pattern: the less the issuer cooperates, the more mathematics the holder pays — and privacy from the issuer itself (who never learns what you prove, or to whom) is only on the table in the third family.
Honest limitations — read before deploying utopia
Linkability: naive credentials let verifiers collude and correlate your sessions. Fix: per-verifierunlinkable presentations (blind issuance, pseudonyms) — AnonCreds and BBS+ handle it; roll your own and you won't.
Holder binding: a stolen credential mustn't verify — presentations must bind to an authenticated holder key.
Revocation: "not revoked" needs proving non-membership in a revocation registry without revealing your credential ID (accumulators again).
Issuer trust: ZK proves the math; it can't prove the birthdate on file was true. Garbage in, zero-knowledge garbage out.
Full circle
Chapter 1 promised proofs that convince but don't reveal. You've now seen every layer: the clock universe (2) that hides exponents, the hashes (3) that seal envelopes, the commitments (4) that lock choices, the interactive dances (5) and their sigma-protocol compression (6), the circuits that swallow entire programs (7) — and finally a citizen proving enough to a bouncer while their identity stays home. That's zero knowledge, end to end.
📌 Week 8 — key takeaways
Selective disclosure = prove predicates (age ≥ 18, country ∈ EU, score ≥ 600) while values stay in your wallet.
The triangle: issuer signs once and goes offline; holder derives per-verifier proofs; verifier checks against public keys.
Set membership (Merkle trees, accumulators) turns ranges into "is your value in the approved set?" — with ZK hiding even the leaf.
The three engineering dragons — unlinkability, revocation, replay/holder binding — each have standard, battle-tested slayers (derived proofs, accumulators, nonce challenges + device keys).
Architecture rule of thumb: less issuer cooperation ⇒ more holder-side math (AnonCreds/BBS+ → SD-JWT → passport SNARKs).
ZK proves the math, never the truth of the issuer's records — garbage in, zero-knowledge garbage out.
🎯
Final Checkpoint: Reveal Less, Prove More
The verifier needs "age ≥ 18: TRUE". With a well-designed ZK credential, what does the holder transmit?
The birthdate, encrypted with the verifier's key.
A proof that a signed attribute satisfies the predicate — no attribute values, no signature material.
A hash of the birthdate the verifier brute-forces against 30,000 dates.
The credential, plus a promise not to store it.
Predicates travel, values stay. (Answer 3 is a real vulnerability of naive designs — a 30,000-entry dictionary defeats any raw hash of a birthdate; proper schemes use ZK proofs or salted commitments.)
In the Merkle set-membership scheme, what stops a 25-year-old from proving "age ≥ 18" if the tree only contains {18,…,25}?
Nothing — they can forge a path.
The bouncer eyeballs them.
Every valid path leads to a leaf in the approved set; there is no path for a non-member value, and the root is the issuer's signed anchor.
The tree is secret.
Membership is hash-verifiable from the signed root; forging a path = finding a SHA-256 collision (Chapter 3's grind, ~2²⁵⁶).
Why does "prove country ∈ EU" leak less than sending your country code, even though the verifier learns the predicate is true?
The verifier learns one bit of a disjunction, not which of the 27 disjuncts is true — the proof is witness-indistinguishable over the whole set.
Because the country code is transmitted twice-hashed.
Because EU countries share a database.
It doesn't — same leakage.
Set membership collapses 27 possibilities into one TRUE. Correlation across sessions drops accordingly — though a singleton set ("country = FR") would leak everything; predicate granularity is a design choice.
Which real limitation of selective disclosure does ZK math NOT solve by itself?
Forging membership paths.
Tampering with signed attributes.
Replay of a presentation to a second verifier.
Whether the issuer's records were accurate in the first place.
ZK proves consistency with issuer signatures — not the truth of the underlying facts. (Replays are handled by challenge/response or fresh holder binding, also outside pure ZK.)