DemoDemo verifier. Checks sample receipts in your browser. The production verifier follows our strict-verification release.
Trust · Verifier

Don't trust
us. Check.

Issue a sample receipt, then verify it. Every step runs in your browser with open-source cryptography. Change one character, or strip the post-quantum signature, and watch it fail.

Checks6, in order
SignaturesEd25519 + ML-DSA-65
Server callsNone
01 Try it

Issue, verify, tamper, verify again.

Everything below runs on your device. Press Verify, flip one character, then press Verify again.

R-Series verifierprofile · demo-hybrid-v1runs in this tab Requests while checking: 0
Receiptloading…

Or click into the receipt and change anything yourself, including the issuer keys, then press Verify. Changed characters are marked in amber.

Checks · in orderall six run · any failure rejects
    Verdict · demo profile · keys issued in this tab
    Waiting for a receipt

    This page makes no request while verifying. Site analytics and Cloudflare's own bot checks run at page load, outside the counter above, which reads your browser's resource timing during the run only. The receipt carries both full issuer public keys, so you can check the same signatures in your own code.

    Demonstration: the keys and the receipt are generated in your browser, using a demo profile shaped like R-Series. The verifier trusts only the keys issued in this tab; it is not yet a verifier for production R-Series receipts. The demo signs the canonical body directly, without the R-Series domain-separation prefix or suite id, so a demo signature is not an R-Series signature. The checks refuse malformed input before any signature is checked: hex fields must be lowercase and of the exact length (Ed25519 key 64 and signature 128 characters, ML-DSA-65 key 3,904 and signature 6,618), and the receipt must be I-JSON as RFC 8785 requires (no repeated member names, unpaired surrogates or non-finite numbers). Fields outside body, digest, issuer and sig are not signed and are not checked. Library: @noble/post-quantum 0.7.1 (FIPS 204 final), @noble/curves 2.4.0, @noble/hashes 2.4.0, bundled as noble.js, sha256 6b0be773a7ddc1b517668c423feac2080e6ba5e98cfa48edc455d3167de5a4be. Checking real DCS receipts is planned.

    This is a demonstration. To see verification on real systems, book a briefing.

    02 What each check proves

    Six channels. One verdict.

    The verifier above runs the same six checks as the instrument on the left. Each one answers a different question, and any single failure rejects the receipt.

    Verification instrument01 / 06
    01 · PARSE

    Is this a receipt at all?

    The text must parse as JSON and contain a body and a signature block. Anything else stops here, before any cryptography runs.

    02 · CANONICALISE

    Exactly which bytes were signed?

    The body is rewritten in its RFC 8785 canonical form: sorted keys, no whitespace, one number format. Two people with the same receipt always get the same bytes.

    03 · DIGEST

    Has anything changed?

    SHA-256 of the canonical bytes must equal the digest in the receipt. Change one character of one field and this check fails. That is what "flip one character" shows.

    04 · ED25519

    Did the issuer sign it, classically?

    The Ed25519 signature is checked against the issuer public key carried in the receipt. This is the leg every existing tool can already verify.

    05 · ML-DSA-65

    Did the issuer sign it, post-quantum?

    The FIPS 204 signature is checked against the same issuer. Removing it is a downgrade attempt: "strip the PQ signature" shows the verifier refusing it.

    06 · POLICY

    Both legs valid, and a known issuer?

    The hybrid suite requires both signatures, and the issuer keys in the receipt must be in the registry the verifier trusts: here, the keys issued in this tab; in production, the published key registry. Only then is the verdict VALID. The production profile also checks the chain and inclusion.

    03 Attacks it catches

    Which check stops which attack.

    AttackWhat the attacker doesStopped at
    Edited bodyChanges a resource, an amount or a timestamp after signingDigest
    Transplanted signatureCopies valid signatures onto a different bodyDigest + both legs
    Stripped PQ legRemoves ML-DSA-65 hoping the verifier settles for Ed25519ML-DSA-65 + policy
    Forged classical legA future quantum attacker forges the Ed25519 signatureML-DSA-65
    Swapped issuerReplaces the issuer keys with their own and re-signs everythingPolicy · unknown issuer
    Unknown profileDeclares a profile the verifier has never seenParse
    Reordered keys (not an attack)Re-serialises the JSON so it looks different but means the same; it stays VALIDCanonicalise
    Wrong chainPresents a receipt under a parent it never hadChain check · production profile
    04 Demo and production

    What this page is, and what it is not.

    THIS PAGE

    A demo profile, in your browser

    Keys and receipt are generated on your device with the open-source @noble libraries. The checks make no network request.

    Demo · in your browser

    PRODUCTION RECEIPTS

    Against the key registry

    Checking real DCS receipts against the published key registry, with key epochs and inclusion proofs.

    Planned

    VERIFIERS

    Three verifiers, one answer

    The existing verifier package checks the first receipt version. Three independent verifier implementations, in JavaScript, Python and Go, agree on every published vector in our test runs. A conformance kit with published, supplementary and reject tiers is in development. A verifier is defined as much by what it refuses as by what it computes. A public v2 verifier comes with the spec and vectors.

    In development

    05 Questions

    About verification.

    Why should I trust the verifier on a DCS page?

    You do not have to. The checks are open and use standard libraries, and the receipt carries both full issuer public keys, so any conforming implementation of RFC 8785, SHA-256, Ed25519 and ML-DSA-65 gets the same signature result. What this page cannot give you is a trusted-issuer answer: it trusts only the keys issued in this tab. A verifier for production R-Series receipts, against the published key registry, is planned.

    Why is the ML-DSA-65 signature so much larger?

    An ML-DSA-65 signature is 3,309 bytes against 64 bytes for Ed25519. That is the price of a post-quantum signature, and it is why receipts store hashes rather than content.

    Does a VALID result mean the action was allowed?

    No. It means the receipt is authentic, unchanged, and from an issuer the verifier trusts. Whether the action was authorised is answered by the intent and governance receipts it links to.

    What if the libraries fail to load?

    The page says so and does not show a verdict. A check that cannot run is never shown as a pass.

    Every check comes from a published standard.

    See which specification each field and each rule relies on.

    See the standards