Solidus
Create Your DID

How Solidus Proves the Credential in Your Wallet Is Actually Yours

The unlinkability implementation described here is unaudited.

Ed25519, the signature primitive underneath this, is heavily scrutinised and is not what is in question.

The problem

A credential is a signed document. A signed document can be copied. If proving something meant handing over a file, then anyone who obtained a copy could prove the same thing: the credential would be a bearer token, valuable to steal.

Holder binding is the answer to "how does the verifier know it is you holding this?"

The mechanism

At issuance, your public key is embedded inside the credential as a confirmation claim. The issuer signs the credential including that key, so the binding cannot be swapped out afterwards without breaking the issuer's signature.

At presentation, you sign a fresh, short-lived proof with the matching private key, and the verifier checks that signature against the key embedded in the credential it just received.

A copied credential is therefore not enough. Presenting it requires the private key, which never leaves your device.

You can confirm the issuer supports this rather than issuing bearer credentials:

$ curl -s https://capture-api.solidus.network/.well-known/openid-credential-issuer
  format                                  : vc+sd-jwt
  cryptographic_binding_methods_supported : ["did:solidus", "jwk"]
  credential_signing_alg_values_supported : ["EdDSA"]

200, checked 2026-07-31. Two binding methods advertised, a did:solidus identifier, or a raw key. That is live confirmation of key-bound issuance, not a claim about it.

Prove the negative yourself

The interesting test is not that a correct key works. It is that a wrong one fails:

$ npm i @solidus-network/sdk        # 0.6.3
# issue a credential with holderPublicKey set,
# then present it signing with a DIFFERENT private key:
#   verification rejects it — key-binding signature mismatch

A mechanism you cannot make fail is a mechanism you have not tested. Run the negative case.

The limit, which is the important half

Holder binding proves the presenter controls a specific private key. That is all it proves.

It does not give you unlinkability. Two presentations bound to the same key can still be correlated by anyone comparing the other fields you disclosed, and, more directly, by the binding key itself if it is reused across verifiers. Being provably you at two places is exactly what makes those two places joinable. The BBS+ implementation referenced here is unaudited.

The argument is good; what is unverified is our implementation, not the shape of the idea.

The complementary defence is a different identifier per verifier, so there is no shared handle to join on in the first place. Those per-verifier identifiers are deliberately never anchored: they resolve to nothing on the public chain, which is the point of them.

Three more things worth knowing

  • The binding is only as strict as the verifier demands. A verifier that does not ask for a key-bound proof will accept a bearer presentation. The mechanism gives a verifier the ability to insist; it cannot make one insist. The key-binding token is where that choice is made.
  • Losing the device means losing the key. Binding to a key you control is a security property and a recovery problem in the same sentence, which is what guardian-based recovery exists for, and a completed recovery mints a new root key.
  • This says nothing about whether the claim is true. Binding proves who is presenting. Whether the issuer was right about what it attested is a separate question, and no cryptography answers it.

Keep reading

How Solidus Proves the Credential in Your Wallet Is Actually Yours · Solidus — Solidus Identity