Find what you share. Keep the rest.
Two lists in. Only the overlap out.
Each item is hashed onto the ristretto255 group and raised to a secret only its owner knows. Blinded twice — once by each party — matching items become equal values, and nothing else can be compared. Run both sides on one page, or do it for real across two browsers.
Both parties run in this tab with independent secrets, so you can watch every message. The sample button makes random address-shaped strings (not real wallets) with a few planted in both lists.
A Alice's list
B Bob's list
You start. Keep this tab open until the end: your secret exponent lives only in this tab's memory, and a reload discards it (you would have to start over).
1 Your list → message 1
Paste your items. Overlap hashes each to the group, raises it to your secret a, shuffles, and packs the result.
2 Paste Party B's reply → result
B's reply holds your values blinded again by b, plus B's own blinded list. You raise B's values to a and compare.
3 Optional: let B learn the result too
Send back B's values blinded by a (in B's order) so B can compute the same overlap. Skip this if only you should learn it.
You respond. Keep this tab open if you want to receive message 3 — your secret b lives only in this tab's memory.
1 Paste message 1 and your list → reply
2 Optional: paste message 3 → result
Only if A chooses to send it. You compare A's re-blinding of your values with what you computed in step 1.
Commutative blinding, in three messages
- Hash to the group. Each item
xbecomes a pointH(x)on ristretto255 — SHA-512 of a domain tag and the item, mapped with the ristretto one-way map (RistrettoPoint.hashToCurve). Ristretto255 is a prime-order group, so there are no small-subgroup tricks. - A blinds and shuffles. A picks a random secret scalar
a, sendsH(xᵢ)·afor every item in a random order (message 1). Withouta, B cannot test any guess against these values. - B blinds twice. B picks a secret
b, returns A's values re-blindedH(xᵢ)·a·bin the order received, plus B's own itemsH(yⱼ)·bin a fresh random order (message 2). - A compares. A computes
H(yⱼ)·b·a. Because scalar multiplication commutes,x = y ⇔ H(x)·ab = H(y)·ba. A matches equal values back to her own items via her private ordering. - Optional symmetry. A returns
H(yⱼ)·b·ain B's order (message 3), and B runs the same comparison. Shuffling means positions never reveal which of B's items matched — only B, who knows his own order, can map them.
Group arithmetic: @noble/curves@1.4.0 (ristretto255). Hashing, randomness and fingerprints: the browser's Web Crypto API. Fingerprints shown next to each message are the first bytes of its SHA-256 — read them aloud to confirm you pasted the right blob.
What leaks, and what doesn't
Leaks by design
- Set sizes. Each side learns how many items the other submitted (the message lengths).
- The intersection — to A always, and to B only if A sends message 3. Its size follows.
- Your chosen items are probes. Anything you put in your list, you learn whether the other side has it. A party can stuff its list with guesses; PSI cannot prevent that.
- Message fingerprints and timing to whatever channel you use to exchange blobs.
Stays hidden
- Every item not in the intersection — from the other party and from anyone who intercepts the blobs (under the decisional Diffie–Hellman assumption, with SHA-512 modelled as a random oracle).
- Which position in a blob corresponds to which item (outputs are shuffled with a CSPRNG).
- The secrets
aandb— they never leave the tab and are discarded on reload. - Your lists from our server: it only serves this page and, if you use the helper, read-only RPC calls.
Known limitations — please read
- Semi-honest security only. The protocol protects against a party who follows the steps but is curious. A malicious party can lie — e.g. A can send a wrong message 3 so B learns a false result, or either side can submit items they don't really hold.
- Small or guessable universes are probeable. If both of you draw from a small known set (say, the top 500 token holders), each side can learn a lot just by choosing what to submit. Agree on list sizes in advance, and treat the intersection as disclosed information.
- No authentication. Blobs carry no identity. Exchange them over a channel where you know who is on the other end, and compare fingerprints.
- Exact matching only. Items must be byte-identical after trimming (and optional lowercasing). Typos and different formats won't match.
- Reduces information exposure, not anonymity. Overlap minimises what two parties reveal to each other; it does not make anyone anonymous or hide on-chain activity.
- Experimental and unaudited. No security review; the group library is a well-known open-source package, but this integration is new. Lists are capped at 5,000 items per side to keep the browser responsive.