Post-quantum · ML-DSA / FIPS 204
The first post-quantum e-signature — on a PDF everyone can still open.
FreeSign puts an ML-DSA signature — the NIST post-quantum standard, FIPS 204, formerly CRYSTALS-Dilithium — alongside the classical signature inside the same signed PDF. Both cover the same bytes. The classical half is untouched, so Adobe Reader, openssl and pyHanko validate the file exactly as before. It is an ordinary free e-signature with a second, quantum-resistant signature riding along.
A “post-quantum PDF signature” that breaks Adobe Reader is not a feature — it is a file nobody can open. Everything below follows from refusing that trade.
1. What we claim — and what we don't
Post-quantum is the most over-claimed word in security marketing right now, so the boundaries come first, before the technical detail.
What we claim
- FreeSign is the first electronic-signature service that signs with post-quantum cryptography. Every PDF signed here carries an ML-DSA signature alongside the classical one — in your browser, without an account, for free. Elsewhere in the ecosystem the post-quantum work so far has been about accepting such signatures: readers are learning to validate them, no signing product produces them.
- The post-quantum signature is a real ML-DSA signature over the same DER-encoded CMS
SignedAttributesthe classical signature covers — not a hash pasted into a comment, not a metadata label. - The ML-DSA public key is bound to the signer by the classical signature, because its SHA-256 sits inside the signed attributes.
- Adding it changes nothing for existing validators. A CI test asserts that
openssl cms -verifystill accepts a co-signed CMS.
What we do not claim
- Not a post-quantum certificate. The ML-DSA key is bound by a signed commitment, not by an RFC 9881 certificate. There is no ML-DSA certificate authority behind it — see § 9.
- Not a quantum-safe identity. Everything that establishes who signed — the leaf certificate, the browser session key, the passkey assertion — is still classical elliptic-curve cryptography. The post-quantum half proves the same attributes were signed, not who signed them, except through the classical binding.
- Not a change of legal class. It is still not a Qualified Electronic Signature. See § 8.
- Not retroactive. Documents signed before this shipped do not carry a post-quantum half — nothing can be added to a PDF after the fact without breaking its signature. /verify tells you which is which, per file.
2. Why now: the ten-year window
We are not going to tell you a quantum computer is about to break your NDA. Nobody honest knows the date, and the ones who claim to are selling something.
The actual reason is duller and firmer: a document signed today has to remain verifiable for as long as it matters legally, and that is measured in years. FreeSign retains signing evidence for about ten years — the period the privacy policy commits to — and commercial contracts, employment agreements and NDAs routinely outlive that. The question is not “will a quantum computer arrive tomorrow”; it is “if one arrives inside the lifetime of this document, does the signature still mean anything?”
You cannot retrofit a signature. Once a PDF is out in the world, the only cryptography protecting it is the cryptography that was in it when it was signed. So the layer has to go in before it is needed, or not at all — which is precisely why it is worth shipping now, and precisely why the addition must not cost you anything today.
3. Why a co-signature, not a replacement
The cryptographic standards below the PDF layer are ready. RFC 9881 defines ML-DSA in X.509 certificates; RFC 9882 defines it in CMS, the container a PDF signature lives in. The PDF layer is not ready: no shipping PDF validator accepts an ML-DSA SignerInfo today.
So the choice was between two options:
Replace the algorithm.
Swap ECDSA for ML-DSA in the SignerInfo. You gain a property nobody can check yet, and you lose Adobe Reader, pyHanko and openssl — every tool your counterparty actually uses. The recipient sees a broken file.
Add alongside it.
Leave the classical signature byte-for-byte as it was and carry the post-quantum one as extra CMS attributes. Conforming validators ignore attributes they do not recognise, so nothing changes for them — and the property is there the day anyone wants to check it.
FreeSign takes the second. The SignerInfo signature stays ECDSA P-256 and the profile stays PAdES-B-T (optionally B-LT). Everything on the trust page and in the openssl verification guide still holds, unchanged, on a co-signed file.
4. How it works: two attributes, one signed payload
When the seal runs, FreeSign generates an ephemeral ML-DSA keypair for that one signature — same lifetime as the ephemeral ECDSA leaf key, wiped from memory as soon as the signature exists, never written to disk or database. Two attributes then go into the CMS, under FreeSign's own IANA PEN arc 1.3.6.1.4.1.65834:
| Key commitment | Signature | |
|---|---|---|
| OID | 1.3.6.1.4.1.65834.1.3 | 1.3.6.1.4.1.65834.1.4 |
| Where it lives | signedAttrs — covered by the classical signature | unsignedAttrs — it cannot sign itself |
| ASN.1 | SEQUENCE { algorithm OID, publicKeyHash OCTET STRING } | SEQUENCE { algorithm OID, publicKey OCTET STRING, signature OCTET STRING } |
| Contents | The ML-DSA parameter-set OID and SHA-256 of the raw ML-DSA public key | The raw FIPS 204 public key and the ML-DSA signature over the DER SignedAttributes |
| What it proves | That this signer, with today's unforgeable classical signature, named that post-quantum key | That the holder of that key signed the very same attributes the classical signature covers |
Why the split is load-bearing
This is the part worth understanding, because it is the difference between a real construction and decoration.
- The commitment must be inside the signed attributes. Otherwise nothing connects the post-quantum key to the signer — anyone could append an unsigned attribute containing their key and their signature. Today's ECDSA signature, which is unforgeable today, is what binds the key to this signer's identity. Key generation therefore has to happen before the signed attributes are built.
- The signature cannot be inside them. It covers those exact bytes; putting it in would require it to sign itself. So it rides as an unsigned attribute — bound in the other direction: it commits to the signed attributes, which commit to
messageDigest = SHA-256(ByteRange), which is the entire signed revision of the PDF. Edit anything and it breaks. - The two halves check each other. A verifier must reject a signature attribute whose public-key hash does not match the signed commitment. FreeSign's verifier fails a swapped key, a bad signature, and a commitment whose signature was stripped out — that last one because the commitment is signed: the signer vouched for a post-quantum key that is no longer in the file. The mirror case is deliberately a caveat rather than a failure: a signature attribute with no commitment is an unbound key, and since anyone can append an unsigned attribute to anyone's PDF, failing on it would let a stranger turn a valid document red. It is reported and ignored. Absent on both sides is merely informational — most PDFs in the world carry neither.
The cost
ML-DSA-65 — the middle parameter set — adds a 1,952-byte public key and a 3,309-byte signature, about 5.3 KB DER-encoded, inside a 32 KB signature slot that has room to spare. Signing costs single-digit milliseconds. Nothing about the ceremony gets slower or larger in any way a signer would notice. All three parameter sets are supported:
| Parameter set | Algorithm OID | Public key | Signature |
|---|---|---|---|
| ML-DSA-44 | 2.16.840.1.101.3.4.3.17 | 1,312 bytes | 2,420 bytes |
| ML-DSA-65 | 2.16.840.1.101.3.4.3.18 | 1,952 bytes | 3,309 bytes |
| ML-DSA-87 | 2.16.840.1.101.3.4.3.19 | 2,592 bytes | 4,627 bytes |
Signing uses “pure” ML-DSA with an empty context string — the mode RFC 9882 mandates for CMS. The implementation is the audited pure-JavaScript @noble/post-quantum, because WebCrypto still has no ML-DSA in any shipping browser or in the Cloudflare Workers runtime.
5. The threat model: retroactive forgery
There is no “harvest now, decrypt later” for a signature. A signature keeps no secret — the document is right there in the open. Collecting signed PDFs today to decrypt in 2040 buys an attacker nothing, because there is nothing encrypted to collect.
The real risk has a different shape: retroactive forgery. An adversary with a cryptographically relevant quantum computer recovers a private key from a public one, forges an ECDSA signature over a document of their choosing, and claims it was signed years earlier — before anyone could have done that.
Defeating that needs two things, and FreeSign already had one of them.
-
1. A signature the quantum computer cannot forge
That is the ML-DSA co-signature. Its security rests on lattice problems, not on the discrete logarithm that Shor's algorithm dismantles.
-
2. Proof that the key binding existed before such a machine did
This part was already there. Every FreeSign signature carries an RFC 3161 timestamp and an OpenTimestamps proof that settles against public Bitcoin block headers. Both are hash-based, and hash functions are the part of classical cryptography that a quantum computer degrades rather than breaks — SHA-256 keeps a large security margin. So they remain meaningful evidence of when something existed even after Q-day.
One refinement mattered enough to build: that OpenTimestamps proof dates the document, and an adversary who can forge signatures could mint a whole new signature structure over the same document — new certificate, new post-quantum key, new commitment — which the document proof would happily date. So every signature carries a second OpenTimestamps anchor, over
SHA-256of the signed attributes themselves (unsigned attribute1.3.6.1.4.1.65834.1.5, embedded in the PDF like the first). Those attributes are where the key commitment lives, so this is the anchor that actually dates the binding. Like any OpenTimestamps proof it is a calendar commitment first and independent evidence once it reaches a Bitcoin block header, usually within an hour or two of signing; /verify says which state a given file is in.
Put together: the commitment names the post-quantum key inside the signed attributes; the classical signature — unforgeable today — binds that key to the signer; and the timestamps, the second anchor in particular, date that binding to today. After Q-day the classical binding is no longer trustworthy on its own, but the timestamped record that it existed beforehand is. That is the whole argument, and it is why the timestamps and the co-signature are worth more together than either is alone.
6. The standards this is built on
None of the cryptography here is home-made. Every piece is a published standard, which is what makes the signature checkable by anyone with off-the-shelf tools rather than only by us.
- FIPS 204 — NIST's Module-Lattice-Based Digital Signature Standard, published August 2024, the algorithm formerly submitted as CRYSTALS-Dilithium. FreeSign signs with the ML-DSA-65 parameter set.
- RFC 9881 defines how ML-DSA keys and signatures are expressed in X.509, and RFC 9882 does the same for CMS — including the algorithm identifiers this page quotes. Our attributes use those identifiers rather than inventing any.
- ETSI EN 319 142 (PAdES) and RFC 5652 (CMS) are what the surrounding signature conforms to, unchanged by the post-quantum addition.
What is new here is not the algorithm — it is that you can use it. The standards have been available to every signing vendor since 2024; FreeSign is the first to put them behind a signing button. Drop a PDF on the home page, sign it, and the file you download carries a post-quantum signature: no account, no licence, no cost, and the document never leaves your browser.
7. Verify it yourself
“Verify it yourself” is this product's entire posture — the same posture as the trust page. A post-quantum claim you have to take on faith is worth nothing, so there are three independent ways to check it, none of which require trusting FreeSign.
-
1. In your browser, at /verify
Drop the signed PDF. The post-quantum co-signature is the sixth check. It confirms that the embedded ML-DSA public key hashes to the value committed inside the signed attributes, and that the ML-DSA signature verifies over those same attribute bytes. The file is never uploaded — the check runs locally, like every other one on that page.
-
2. With the open-source verifier
The exact client-side code served at /verify is published under the MIT licence at github.com/free-sign/verifier, and it runs under Node as well as in a browser. Read it, audit it, run it against our PDFs or anyone else's.
-
3. From a shell
node tools/validate-sealed-pdf.mjs signed.pdfruns the whole validator ladder in one shot; the post-quantum verdict is step [7]. And the point that matters most for interoperability —openssl cms -verifyandpyHanko sign validateaccepting a co-signed file exactly as they accept a classical one — you can reproduce in a terminal in under a minute with the verification guide.
Tampering tells the same story from the other side, and this is pinned by continuous-integration tests: flip a bit in the ML-DSA signature, swap the embedded public key, or strip the unsigned attribute entirely, and only the post-quantum check fails — the classical CMS check stays green. Which is exactly why the sixth check has to exist as its own verdict rather than being folded into the first.
8. What this does not change: the legal class
The output is a PAdES signed PDF per ETSI EN 319 142, at the B-T baseline (optionally B-LT), and the evidence model is the same one described everywhere else on this site: intent, attribution, association with the record, retention, timestamps, and tamper detection. FreeSign is designed around eIDAS Article 26 advanced-electronic-signature evidence and is valid under the US ESIGN Act and UETA.
The post-quantum layer does not change the legal class of the signature. FreeSign is not a Qualified Electronic Signature (QES) and 2Dynamic Games is not a Qualified Trust Service Provider — with the co-signature exactly as without it.
It is worth being blunt about why, because “stronger cryptography” sounds like it should mean “more legally binding”, and it does not. The eIDAS tiers — SES, AES, QES — are about who issued the certificate, on what device the key lives, and what audits the provider passed. None of those are properties of the signature algorithm. A QES made with ECDSA outranks, legally, an advanced signature made with ML-DSA. What the post-quantum layer buys is durability of the evidence, not tier.
The full legal framing — the SES/AES/QES ladder, when QES is actually required, and the honest limits — is in the FAQ. None of this is legal advice; for a high-stakes document, confirm the required form in your jurisdiction.
9. What we deliberately did not build
Each of these was a decision, not an oversight.
- No post-quantum certificate authority. The ML-DSA key is bound by the signed commitment, not by an RFC 9881 certificate. A second, ML-DSA certificate chain is worth building once something in the ecosystem validates it; until then it would be complexity with no verifier.
- No ML-DSA in the
SignerInfo. For the reason in § 3: it would break every validator that exists. When ISO and Adobe formalise the PDF algorithms, that door opens. - The browser session key and the two envelope signatures stay ECDSA P-256. The session key is a minutes-long anti-replay binding with no long-term value, and it lives as a non-extractable
CryptoKeyin the browser. Moving it to ML-DSA would mean handling the private key as a plain byte array in JavaScript — a real security downgrade, today, for a benefit that does not apply to a key that expires in minutes. - Passkeys stay ES256. The algorithm is the authenticator's choice, not ours — no shipping platform authenticator offers a post-quantum option.
The OpenTimestamps anchor over the signed attributes described in § 5 was the next step on this list, and it shipped: the key commitment now has its own hash-based proof of existence rather than relying on the document anchor. Next, and only once the ecosystem can check them, come RFC 9881 certificates and eventually a native post-quantum signature.
Sign a PDF and check the sixth line yourself
Sign a document, then drop the result on the verifier. Both run entirely in your browser; neither ever sees the file.
Sign a PDF now →