ParaID  Beta

Prove a claim. Keep the data.

A verifier asks a question, like “is this person 18 or older?”. Your device answers yes or no, with cryptographic proof. The passport fields behind the answer never leave your device, and the relay never sees them either.

The demo below runs entirely in this page. Your wallet holds a real credential and answers requests. Screen-flash liveness is our app-less identity research.

  1. 1. An issuer seals the facts

    A trusted issuer writes each field into a salted, sealed hash and signs the set once with ML-DSA-65 (FIPS 204). The issuer identity is bound to that key as a DID.
  2. 2. Your device answers

    The wallet opens the sealed answer plus the key binding, and signs the verifier’s fresh nonce with the holder key. You see precisely what will be shared before it leaves the device.
  3. 3. The verifier checks offline

    The verifier recomputes the chain, checks the issuer signature, confirms the credential is bound to the presenting device and that the answer is fresh. It learns the answer and who vouched for it. Nothing else.
● This box runs on your device only network requests during demo: 0

1 · Demo issuer

Issues a demo passport credential on this device. In production this is a municipality, bank or employer.

2 · Your wallet (this device)

Issue a credential first.

3 · Verifier

Checks the proof chain, the ML-DSA-65 issuer signature, the holder-key binding and the freshness nonce. Works offline.

Session nonce: -

The counter above is measured live by your own browser (Performance API), not written by us. Want harder proof? Turn on airplane mode and run the demo again: everything keeps working.

How it works, in one picture

The trick is a Merkle tree. Each passport fact is sealed into its own hash (a leaf). Pairs of hashes are hashed together, again and again, up to a single fingerprint at the top: the root. The issuer signs only that root.

                        ROOT  <-- issuer signs THIS with ML-DSA-65
                    /          \
             H(1,2)              H(3,4)
            /      \            /      \
        H(name) H(birth)   H(nat)  H(doc)   ... H(age_over_18=yes)  H(holder key)
           |       |          |       |              |                    |
        "name"  "1994.."    "NL"   "DEMO.."    the answer          your device
        stays home stays home  stays home stays home     shared              bound
1Only the answer opens. To prove “18+ = yes” the wallet reveals just that one leaf plus the few sibling hashes on the path up to the root. From those you can recompute the root, but you can never run the hashes backwards to learn the birthdate.
2The signature proves who. The root carries the issuer’s ML-DSA-65 signature. The issuer’s identity (its DID) is the hash of its own public key, so a signature can never be re-attributed to someone else, and any change to any fact changes the root and breaks the signature.
3The binding proves whose. One leaf is the hash of your device key. You sign the verifier’s fresh nonce with that key, so the proof only works from your device and only for this one check. A copied or replayed proof fails.
4The registry proves it is real. Anyone can check that the signing issuer is on Paramant’s public, transparency-logged registry, and not on its revocation list.

How to read the results

1. The green result box, line by line

On success the verifier shows five rows, each a separate check that had to pass.

✓ 18+? YESThe answer, cryptographically proven, without ever showing the birthdate behind it.
issuerWho vouched for the facts. The code is derived from the issuer’s key, so it cannot point to anyone else.
issuer signatureThe sealed facts really were signed by that issuer, and nothing was changed afterwards.
holderLocked to the key of the device showing it, and made just now for this check. Stolen or replayed proofs fail here.
fields receivedThe complete list of what actually reached the verifier. Everything else stayed sealed on the device.

2. Is the issuer trustworthy? (the registry check)

One optional button checks the public issuer registry. Four possible outcomes:

registeredThe issuer is in the public registry, anchored in the transparency log, so it cannot be quietly added or removed. Trust the credential.
demo onlyThis demo invents its own issuer inside your tab, so it is deliberately not registered. Real credentials come from registered issuers only.
issuer revokedThe issuer was withdrawn. The math may still check out, but do not trust its credentials. Revocations stay visible forever.
credential revokedThe issuer is fine, but this one credential was withdrawn (lost phone, expired document, error). Checked against the issuer’s status list of opaque hashes, no personal data.

3. Your privacy, shown live

network: 0Issuing and proving make zero network requests. Everything runs on your device.
network: 1Only the optional registry check fetches the public issuer list, once. It sends nothing about you, and the counter turning red is the counter proving itself.

4. When it fails

✗ rejectedOne check failed: tampered data, a key that does not match, or an expired or foreign nonce. The verifier names the exact reason.

Beta means beta. The honest list:

  • The demo issuer is generated in your tab; it is not a real authority. Production needs identity-proofing at a trusted issuer.
  • No revocation yet: a real deployment adds a status list so issuers can withdraw credentials.
  • Repeated proofs from the same credential are linkable to each other. The zero-knowledge route (STARK over the same sealed structure) removes that; it is on the roadmap, not in this beta.
  • This is an advanced cryptographic attestation, not an eIDAS-qualified identity scheme.
  • This page makes no network calls. Open devtools: the network tab stays empty while you run the demo.