A Different Identity for Every Relying Party
The unlinkability implementation described here is unaudited.
It is not the identifier a relying party sees when you present a credential to it. Every service you connect to instead gets a different, deliberately unanchored identifier (a pairwise DID) derived from your one identity but never itself written to the chain. Two relying parties comparing notes have no shared number to compare, because neither was ever shown the same one. This shipped to production on 2026-07-12, wired through Solidus Identity's own presentation flow, and has been running under internal dogfood since, seven consecutive test sessions, seven for seven.
See it fail to resolve
The strongest proof of "never anchored" isn't a claim, it's a command anyone can run themselves: try to resolve a pairwise DID against the public chain and watch it come back empty.
Generate one, the auth SDK derives them the same way present.ts does when you actually present a
credential, then run the exact JSON-RPC resolution call this network exposes for any did:solidus
identifier:
curl -X POST https://rpc.solidus.network \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "solidus_didResolve",
"params": ["<your-pairwise-did>"],
"id": 1
}'
Point it at your one registered did:solidus and you get back a real DID Document, keys,
authentication methods, the works. Point the same call at a pairwise DID and the response is
{"result": null}. Nothing malformed, nothing rejected, just nothing there, because nothing was
ever written. A made-up identifier and a deliberately-never-anchored one look identical from the
outside, and that's the point: there is no ledger entry to correlate against in the first place.
The mechanism, plainly
A pairwise DID isn't a second identity you manage, it's computed. Your wallet derives it from your
existing seed plus the name of the relying party you're talking to, using a keyed derivation scheme
in packages/@solidus/auth/src/pairwise.ts. Run the derivation again with the same seed and the same
relying party and you get the identical identifier back. That's the deliberate design point:
deterministic doesn't mean unlinkable-into-anonymous, it means the same relying party recognizes
you on your next visit without ever needing to know what identifier anyone else sees you as. Nothing
is stored per relationship, no per-verifier key file, no separate backup path. Everything derives
from the one seed your wallet already protects. The BBS+ implementation referenced here is unaudited.
Why two verifiers can't compare notes
This is the actual privacy property, and it's worth stating precisely rather than rounding it up. What pairwise derivation defeats is identifier-level correlation: if Verifier A and Verifier B both hold your credential presentations and try to line up the identifiers they were shown, they find nothing in common, because they were never shown the same one, and neither resolves to anything a third party could look up either.
That is the whole claim. It says nothing about IP address correlation, request timing, device fingerprinting, or two relying parties simply comparing notes out of band on data they each independently collected about you through some other channel. If Verifier A and Verifier B share a data broker or a common analytics vendor, that correlation happens outside this mechanism entirely, and no identifier scheme touches it. Pairwise DIDs close one specific door (the naive one, where the identifier itself is the shared handle) not every door.
What this isn't
A pairwise DID's unanchored status is a separate fact from did:solidus's registry status, and it's
easy to blur the two. The method, did:solidus, is registered in the W3C DID Method Registry;
that's a statement about the scheme, not about any individual identifier issued under it. A specific
pairwise DID derived under that method is deliberately never anchored and never resolves: the method
being registered has no bearing on whether one particular derived identifier lives on-chain.
It's also not evidence of scale. What's shipped is internal dogfood, seven consecutive test sessions, since 2026-07-12, not a user-tested or battle-tested claim. One more boundary worth naming: guardian-based social key recovery rotates your wallet's root key, and every pairwise identity is derived from that root, recover your account and you look new to every relying party again. That's a deliberate consequence of severing old handles when a key is recovered, not a bug.
Where this fits
Pairwise DIDs are one piece of the presentation flow how it works already introduces: this page is that mechanism's deep dive. They solve return-visit recognition without a shared identifier. And a pairwise DID isn't the reuse story either, for how one credential travels across unrelated relying parties, see credential portability. If you want the resolution call itself explained in more depth, including how a DID Document is shaped, that's resolving a DID.
The term itself, precisely defined, including the derivation tradeoffs Solidus made and didn't, lives in the Lexicon's Pairwise DID entry. This page is the product experience; that's where the definition is owned.

